diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -4383,7 +4383,11 @@
 class UnaryTransformType : public Type {
 public:
   enum UTTKind {
-    EnumUnderlyingType
+    EnumUnderlyingType,
+    RemoveReferenceType,
+    RemoveCV,
+    RemoveConst,
+    RemoveVolatile,
   };
 
 private:
diff --git a/clang/include/clang/Basic/Specifiers.h b/clang/include/clang/Basic/Specifiers.h
--- a/clang/include/clang/Basic/Specifiers.h
+++ b/clang/include/clang/Basic/Specifiers.h
@@ -83,16 +83,20 @@
     TST_struct,
     TST_class,        // C++ class type
     TST_interface,    // C++ (Microsoft-specific) __interface type
+    TST_decltype,         // C++11 decltype
+    TST_typeofExpr,
     TST_typename,     // Typedef, C++ class-name or enum name, etc.
     TST_typeofType,
-    TST_typeofExpr,
-    TST_decltype,         // C++11 decltype
     TST_underlyingType,   // __underlying_type for C++11
+    TST_removeReferenceType, // __remove_reference
+    TST_removeCV, // __remove_cv
+    TST_removeConst, // __remove_const
+    TST_removeVolatile, // __remove_volatile
+    TST_atomic,           // C11 _Atomic
     TST_auto,             // C++11 auto
     TST_decltype_auto,    // C++1y decltype(auto)
     TST_auto_type,        // __auto_type extension
     TST_unknown_anytype,  // __unknown_anytype extension
-    TST_atomic,           // C11 _Atomic
 #define GENERIC_IMAGE_TYPE(ImgType, Id) TST_##ImgType##_t, // OpenCL image types
 #include "clang/Basic/OpenCLImageTypes.def"
     TST_error // erroneous type
diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -487,6 +487,10 @@
 TYPE_TRAIT_1(__has_unique_object_representations,
              HasUniqueObjectRepresentations, KEYCXX)
 KEYWORD(__underlying_type           , KEYCXX)
+KEYWORD(__remove_reference          , KEYCXX)
+KEYWORD(__remove_cv                        , KEYCXX)
+KEYWORD(__remove_const                     , KEYCXX)
+KEYWORD(__remove_volatile                  , KEYCXX)
 
 // Clang-only C++ Type Traits
 TYPE_TRAIT_2(__reference_binds_to_temporary, ReferenceBindsToTemporary, KEYCXX)
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -2715,6 +2715,8 @@
                                          SourceLocation StartLoc,
                                          SourceLocation EndLoc);
   void ParseUnderlyingTypeSpecifier(DeclSpec &DS);
+  DeclSpec::TST TypeTransformTokToDeclSpec();
+  void ParseTypeTransformTypeSpecifier(DeclSpec &DS);
   void ParseAtomicSpecifier(DeclSpec &DS);
 
   ExprResult ParseAlignArgument(SourceLocation Start,
diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h
--- a/clang/include/clang/Sema/DeclSpec.h
+++ b/clang/include/clang/Sema/DeclSpec.h
@@ -294,16 +294,20 @@
   static const TST TST_struct = clang::TST_struct;
   static const TST TST_interface = clang::TST_interface;
   static const TST TST_class = clang::TST_class;
-  static const TST TST_typename = clang::TST_typename;
-  static const TST TST_typeofType = clang::TST_typeofType;
-  static const TST TST_typeofExpr = clang::TST_typeofExpr;
   static const TST TST_decltype = clang::TST_decltype;
   static const TST TST_decltype_auto = clang::TST_decltype_auto;
+  static const TST TST_typeofExpr = clang::TST_typeofExpr;
+  static const TST TST_typename = clang::TST_typename;
+  static const TST TST_typeofType = clang::TST_typeofType;
   static const TST TST_underlyingType = clang::TST_underlyingType;
+  static const TST TST_removeReferenceType = clang::TST_removeReferenceType;
+  static const TST TST_removeCV = clang::TST_removeCV;
+  static const TST TST_removeConst = clang::TST_removeConst;
+  static const TST TST_removeVolatile = clang::TST_removeVolatile;
+  static const TST TST_atomic = clang::TST_atomic;
   static const TST TST_auto = clang::TST_auto;
   static const TST TST_auto_type = clang::TST_auto_type;
   static const TST TST_unknown_anytype = clang::TST_unknown_anytype;
-  static const TST TST_atomic = clang::TST_atomic;
 #define GENERIC_IMAGE_TYPE(ImgType, Id) \
   static const TST TST_##ImgType##_t = clang::TST_##ImgType##_t;
 #include "clang/Basic/OpenCLImageTypes.def"
@@ -409,8 +413,7 @@
   ObjCDeclSpec *ObjCQualifiers;
 
   static bool isTypeRep(TST T) {
-    return (T == TST_typename || T == TST_typeofType ||
-            T == TST_underlyingType || T == TST_atomic);
+    return (TST_typename <= T && T <= TST_atomic);
   }
   static bool isExprRep(TST T) {
     return (T == TST_typeofExpr || T == TST_decltype);
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -3497,6 +3497,20 @@
       case UnaryTransformType::EnumUnderlyingType:
         Out << "3eut";
         break;
+      case UnaryTransformType::RemoveReferenceType:
+        Out << "3rrt";
+        break;
+      case UnaryTransformType::RemoveCV:
+        Out << "3rcvt";
+        break;
+        break;
+      case UnaryTransformType::RemoveConst:
+        Out << "3rct";
+        break;
+        break;
+      case UnaryTransformType::RemoveVolatile:
+        Out << "3rvt";
+        break;
     }
   }
 
diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp
--- a/clang/lib/AST/JSONNodeDumper.cpp
+++ b/clang/lib/AST/JSONNodeDumper.cpp
@@ -621,6 +621,18 @@
   case UnaryTransformType::EnumUnderlyingType:
     JOS.attribute("transformKind", "underlying_type");
     break;
+  case UnaryTransformType::RemoveReferenceType:
+    JOS.attribute("transformKind", "remove_reference");
+    break;
+  case UnaryTransformType::RemoveCV:
+    JOS.attribute("transformKind", "remove_cv");
+    break;
+  case UnaryTransformType::RemoveConst:
+    JOS.attribute("transformKind", "remove_const");
+    break;
+  case UnaryTransformType::RemoveVolatile:
+    JOS.attribute("transformKind", "remove_volatile");
+    break;
   }
 }
 
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -1220,6 +1220,18 @@
   case UnaryTransformType::EnumUnderlyingType:
     OS << " underlying_type";
     break;
+  case UnaryTransformType::RemoveReferenceType:
+    OS << " remove_reference";
+    break;
+  case UnaryTransformType::RemoveCV:
+    OS << " remove_cv";
+    break;
+  case UnaryTransformType::RemoveConst:
+    OS << " remove_const";
+    break;
+  case UnaryTransformType::RemoveVolatile:
+    OS << " remove_volatile";
+    break;
   }
 }
 
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -10,7 +10,6 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/AST/PrettyPrinter.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclBase.h"
@@ -19,8 +18,10 @@
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/PrettyPrinter.h"
 #include "clang/AST/TemplateBase.h"
 #include "clang/AST/TemplateName.h"
+#include "clang/AST/TextNodeDumper.h"
 #include "clang/AST/Type.h"
 #include "clang/Basic/AddressSpaces.h"
 #include "clang/Basic/ExceptionSpecificationType.h"
@@ -1019,16 +1020,15 @@
                                             raw_ostream &OS) {
   IncludeStrongLifetimeRAII Strong(Policy);
 
-  switch (T->getUTTKind()) {
-    case UnaryTransformType::EnumUnderlyingType:
-      OS << "__underlying_type(";
-      print(T->getBaseType(), OS, StringRef());
-      OS << ')';
-      spaceBeforePlaceHolder(OS);
-      return;
-  }
-
-  printBefore(T->getBaseType(), OS);
+  TextNodeDumper textDumper(
+      OS, /*ShowColors*/ false,
+      &T->getAsRecordDecl()->getASTContext().getSourceManager(), Policy,
+      /*Traits*/ nullptr);
+  textDumper.VisitUnaryTransformType(T);
+  OS << '(';
+  print(T->getBaseType(), OS, StringRef());
+  OS << ')';
+  spaceBeforePlaceHolder(OS);
 }
 
 void TypePrinter::printUnaryTransformAfter(const UnaryTransformType *T,
@@ -1037,6 +1037,10 @@
 
   switch (T->getUTTKind()) {
     case UnaryTransformType::EnumUnderlyingType:
+    case UnaryTransformType::RemoveReferenceType:
+    case UnaryTransformType::RemoveCV:
+    case UnaryTransformType::RemoveConst:
+    case UnaryTransformType::RemoveVolatile:
       return;
   }
 
diff --git a/clang/lib/Format/FormatToken.cpp b/clang/lib/Format/FormatToken.cpp
--- a/clang/lib/Format/FormatToken.cpp
+++ b/clang/lib/Format/FormatToken.cpp
@@ -55,6 +55,10 @@
   case tok::kw_wchar_t:
   case tok::kw_bool:
   case tok::kw___underlying_type:
+  case tok::kw___remove_reference:
+  case tok::kw___remove_cv:
+  case tok::kw___remove_const:
+  case tok::kw___remove_volatile:
   case tok::annot_typename:
   case tok::kw_char8_t:
   case tok::kw_char16_t:
diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp
--- a/clang/lib/Lex/PPMacroExpansion.cpp
+++ b/clang/lib/Lex/PPMacroExpansion.cpp
@@ -1662,6 +1662,10 @@
               .Case("__array_extent", true)
               .Case("__reference_binds_to_temporary", true)
               .Case("__underlying_type", true)
+              .Case("__remove_reference", true)
+              .Case("__remove_cv", true)
+              .Case("__remove_const", true)
+              .Case("__remove_volatile", true)
               .Default(false);
         } else {
           return llvm::StringSwitch<bool>(II->getName())
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -4012,6 +4012,13 @@
     case tok::kw___underlying_type:
       ParseUnderlyingTypeSpecifier(DS);
       continue;
+        
+    case tok::kw___remove_reference:
+    case tok::kw___remove_cv:
+    case tok::kw___remove_const:
+    case tok::kw___remove_volatile:
+      ParseTypeTransformTypeSpecifier(DS);
+      continue;
 
     case tok::kw__Atomic:
       // C11 6.7.2.4/4:
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -1092,6 +1092,52 @@
   DS.setTypeofParensRange(T.getRange());
 }
 
+DeclSpec::TST Parser::TypeTransformTokToDeclSpec() {
+  switch (Tok.getKind()) {
+      case tok::kw___remove_reference:
+        return DeclSpec::TST_removeReferenceType;
+      case tok::kw___remove_cv:
+        return DeclSpec::TST_removeCV;
+      case tok::kw___remove_const:
+        return DeclSpec::TST_removeConst;
+      case tok::kw___remove_volatile:
+        return DeclSpec::TST_removeVolatile;
+      default:
+        assert(false && "Not a reference type specifier");
+  }
+}
+
+void Parser::ParseTypeTransformTypeSpecifier(DeclSpec &DS) {
+  // FIXME: static_cast<DeclSpec::TST>(Tok.getKind() - base);
+  DeclSpec::TST TypeTransformTST = TypeTransformTokToDeclSpec();
+
+  SourceLocation StartLoc = ConsumeToken();
+  BalancedDelimiterTracker T(*this, tok::l_paren);
+  if (T.expectAndConsume(diag::err_expected_lparen_after,
+                         "type transformation builtin", tok::r_paren))
+    return;
+
+  TypeResult BaseTyResult = ParseTypeName();
+  if (BaseTyResult.isInvalid()) {
+    SkipUntil(tok::r_paren, StopAtSemi);
+    return;
+  }
+
+  T.consumeClose();
+  if (T.getCloseLocation().isInvalid()) return;
+
+  const char *PrevSpec;
+  unsigned DiagID;
+  if (DS.SetTypeSpecType(TypeTransformTST,
+                         StartLoc, PrevSpec,
+                         DiagID, BaseTyResult.get(),
+                         Actions.getASTContext().getPrintingPolicy())) {
+    Diag(StartLoc, DiagID) << PrevSpec;
+  }
+  DS.setTypeofParensRange(T.getRange());
+}
+
+
 /// ParseBaseTypeSpecifier - Parse a C++ base-type-specifier which is either a
 /// class name or decltype-specifier. Note that we only check that the result
 /// names a type; semantic analysis will need to verify that the type names a
diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp
--- a/clang/lib/Sema/DeclSpec.cpp
+++ b/clang/lib/Sema/DeclSpec.cpp
@@ -383,6 +383,10 @@
       return false;
 
     case TST_underlyingType:
+    case TST_removeReferenceType:
+    case TST_removeCV:
+    case TST_removeConst:
+    case TST_removeVolatile:
     case TST_typename:
     case TST_typeofType: {
       QualType QT = DS.getRepAsType().get();
@@ -562,6 +566,10 @@
   case DeclSpec::TST_decltype:    return "(decltype)";
   case DeclSpec::TST_decltype_auto: return "decltype(auto)";
   case DeclSpec::TST_underlyingType: return "__underlying_type";
+  case DeclSpec::TST_removeReferenceType: return "__remove_reference";
+  case DeclSpec::TST_removeCV: return "__remove_cv";
+  case DeclSpec::TST_removeConst: return "__remove_const";
+  case DeclSpec::TST_removeVolatile: return "__remove_volatile";
   case DeclSpec::TST_unknown_anytype: return "__unknown_anytype";
   case DeclSpec::TST_atomic: return "_Atomic";
 #define GENERIC_IMAGE_TYPE(ImgType, Id) \
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -143,6 +143,10 @@
   case tok::kw_wchar_t:
   case tok::kw_bool:
   case tok::kw___underlying_type:
+  case tok::kw___remove_reference:
+  case tok::kw___remove_cv:
+  case tok::kw___remove_const:
+  case tok::kw___remove_volatile:
   case tok::kw___auto_type:
     return true;
 
@@ -5470,6 +5474,10 @@
   case DeclSpec::TST_typename:
   case DeclSpec::TST_typeofType:
   case DeclSpec::TST_underlyingType:
+  case DeclSpec::TST_removeReferenceType:
+  case DeclSpec::TST_removeCV:
+  case DeclSpec::TST_removeConst:
+  case DeclSpec::TST_removeVolatile:
   case DeclSpec::TST_atomic: {
     // Grab the type from the parser.
     TypeSourceInfo *TSI = nullptr;
diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp
--- a/clang/lib/Sema/SemaTemplateVariadic.cpp
+++ b/clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -838,6 +838,10 @@
   case TST_typename:
   case TST_typeofType:
   case TST_underlyingType:
+  case TST_removeReferenceType:
+  case TST_removeCV:
+  case TST_removeConst:
+  case TST_removeVolatile:
   case TST_atomic: {
     QualType T = DS.getRepAsType().get();
     if (!T.isNull() && T->containsUnexpandedParameterPack())
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -1253,6 +1253,24 @@
   return OpenCLAccessAttr::Keyword_read_only;
 }
 
+static UnaryTransformType::UTTKind
+TSTToUnaryTransformType(DeclSpec::TST SwitchTST) {
+  switch (SwitchTST) {
+  case TST_removeCV:
+    return UnaryTransformType::RemoveCV;
+  case TST_removeConst:
+    return UnaryTransformType::RemoveConst;
+  case TST_removeVolatile:
+    return UnaryTransformType::RemoveVolatile;
+  case TST_removeReferenceType:
+    return UnaryTransformType::RemoveReferenceType;
+  case TST_underlyingType:
+    return UnaryTransformType::EnumUnderlyingType;
+  default:
+    llvm_unreachable("Cannot map TST to unary transform type");
+  }
+}
+
 static QualType ConvertConstrainedAutoDeclSpecToType(Sema &S, DeclSpec &DS,
                                                      AutoTypeKeyword AutoKW) {
   assert(DS.isConstrainedAuto());
@@ -1605,16 +1623,23 @@
     break;
   }
   case DeclSpec::TST_underlyingType:
+  case DeclSpec::TST_removeReferenceType:
+  case DeclSpec::TST_removeCV:
+  case DeclSpec::TST_removeConst:
+  case DeclSpec::TST_removeVolatile: {
     Result = S.GetTypeFromParser(DS.getRepAsType());
-    assert(!Result.isNull() && "Didn't get a type for __underlying_type?");
+    assert(!Result.isNull() &&
+           "Type transform builtin may not have received a type.");
     Result = S.BuildUnaryTransformType(Result,
-                                       UnaryTransformType::EnumUnderlyingType,
+                                       TSTToUnaryTransformType(DS.getTypeSpecType()),
                                        DS.getTypeSpecTypeLoc());
     if (Result.isNull()) {
-      Result = Context.IntTy;
+      if (DS.getTypeSpecType() == DeclSpec::TST_underlyingType)
+        Result = Context.IntTy;
       declarator.setInvalidType(true);
     }
     break;
+  }
 
   case DeclSpec::TST_auto:
     if (DS.isConstrainedAuto()) {
@@ -5660,8 +5685,9 @@
       TL.setUnderlyingTInfo(TInfo);
     }
     void VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
-      // FIXME: This holds only because we only have one unary transform.
-      assert(DS.getTypeSpecType() == DeclSpec::TST_underlyingType);
+      // Make sure it is a unary transform type
+      assert(DS.getTypeSpecType() >= DeclSpec::TST_underlyingType &&
+             DS.getTypeSpecType() <= DeclSpec::TST_removeVolatile);
       TL.setKWLoc(DS.getTypeSpecTypeLoc());
       TL.setParensRange(DS.getTypeofParensRange());
       assert(DS.getRepAsType());
@@ -8604,6 +8630,36 @@
       return Context.getUnaryTransformType(BaseType, Underlying,
                                         UnaryTransformType::EnumUnderlyingType);
     }
+  case UnaryTransformType::RemoveReferenceType: {
+    QualType Underlying = BaseType.getNonReferenceType();
+    return Context.getUnaryTransformType(BaseType, Underlying,
+                                         UnaryTransformType::RemoveReferenceType);
+  }
+  case UnaryTransformType::RemoveCV: {
+    SplitQualType Split = BaseType.getSplitUnqualifiedType();
+    Qualifiers Quals = BaseType.getQualifiers();
+    Quals.removeConst();
+    Quals.removeVolatile();
+    QualType Underlying(Split.Ty, Quals.getAsOpaqueValue());
+    return Context.getUnaryTransformType(BaseType, Underlying,
+                                         UnaryTransformType::RemoveCV);
+  }
+  case UnaryTransformType::RemoveConst: {
+    SplitQualType Split = BaseType.getSplitUnqualifiedType();
+    Qualifiers Quals = BaseType.getQualifiers();
+    Quals.removeConst();
+    QualType Underlying(Split.Ty, Quals.getAsOpaqueValue());
+    return Context.getUnaryTransformType(BaseType, Underlying,
+                                         UnaryTransformType::RemoveConst);
+  }
+  case UnaryTransformType::RemoveVolatile: {
+    SplitQualType Split = BaseType.getSplitUnqualifiedType();
+    Qualifiers Quals = BaseType.getQualifiers();
+    Quals.removeVolatile();
+    QualType Underlying(Split.Ty, Quals.getAsOpaqueValue());
+    return Context.getUnaryTransformType(BaseType, Underlying,
+                                         UnaryTransformType::RemoveVolatile);
+  }
   }
   llvm_unreachable("unknown unary transform type");
 }
diff --git a/clang/test/SemaCXX/remove_cv.cpp b/clang/test/SemaCXX/remove_cv.cpp
new file mode 100644
--- /dev/null
+++ b/clang/test/SemaCXX/remove_cv.cpp
@@ -0,0 +1,58 @@
+// RUN: %clang_cc1 -std=c++11 %s
+
+template<class T>
+struct remove_const
+{
+  typedef __remove_const(T) type;
+};
+
+template<class T>
+struct remove_volatile
+{
+  typedef __remove_volatile(T) type;
+};
+
+template<class T>
+struct remove_cv
+{
+  typedef __remove_cv(T) type;
+};
+
+template<class T>
+struct test
+{
+  static const bool value =
+    __is_same(typename remove_const<T>::type, T) &&
+    __is_same(typename remove_const<const volatile T>::type, volatile T) &&
+    __is_same(typename remove_const<const T>::type, T) &&
+
+    __is_same(typename remove_volatile<T>::type, T) &&
+    __is_same(typename remove_volatile<const volatile T>::type, const T) &&
+    __is_same(typename remove_volatile<volatile T>::type, T) &&
+
+    __is_same(typename remove_cv<const volatile T>::type, T) &&
+    __is_same(typename remove_cv<T>::type, T) &&
+    __is_same(typename remove_cv<const T>::type, T) &&
+    __is_same(typename remove_cv<volatile T>::type, T);
+};
+
+struct Foo { };
+
+template<class T>
+struct Bar { };
+
+template<class T>
+class Baz { };
+
+class Biz;
+
+void x() { }
+
+static_assert(test<int>::value, "");
+static_assert(test<int[]>::value, "");
+static_assert(test<int[8]>::value, "");
+static_assert(test<Foo>::value, "");
+static_assert(test<Bar<int>>::value, "");
+static_assert(test<Baz<int>>::value, "");
+static_assert(test<Biz>::value, "");
+static_assert(test<decltype(x)>::value, "");
diff --git a/clang/test/SemaCXX/remove_reference.cpp b/clang/test/SemaCXX/remove_reference.cpp
new file mode 100644
--- /dev/null
+++ b/clang/test/SemaCXX/remove_reference.cpp
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -std=c++11 %s
+
+template<class T>
+struct test_remove_ref_trait
+{
+  typedef __remove_reference(T) type;
+};
+
+template<class T>
+struct test_remove_ref
+{
+  static const bool value = __is_same(typename test_remove_ref_trait<T>::type, T)  &&
+                            __is_same(typename test_remove_ref_trait<T&>::type, T) &&
+                            __is_same(typename test_remove_ref_trait<T&&>::type, T);
+};
+
+struct Foo { };
+
+template<class T>
+struct Bar { };
+
+template<class T>
+class Baz { };
+
+class Biz;
+
+void x() { }
+
+static_assert(test_remove_ref<int>::value, "");
+static_assert(test_remove_ref<int[]>::value, "");
+static_assert(test_remove_ref<int[8]>::value, "");
+static_assert(test_remove_ref<Foo>::value, "");
+static_assert(test_remove_ref<Bar<int>>::value, "");
+static_assert(test_remove_ref<Baz<int>>::value, "");
+static_assert(test_remove_ref<int*>::value, "");
+static_assert(test_remove_ref<int const>::value, "");
+static_assert(test_remove_ref<int(int)>::value, "");
+static_assert(test_remove_ref<Biz>::value, "");
+static_assert(test_remove_ref<decltype(x)>::value, "");
+