zoecarver created this revision.
zoecarver added reviewers: EricWF, eli.friedman, rsmith, craig.topper.
Herald added subscribers: libcxx-commits, cfe-commits, jfb, christof.
Herald added projects: clang, libc++.

This patch adds builtin type traits to transform reference types. Specifically, 
it adds `__add_lvalue_reference`, `__add_rvalue_reference`, and 
`__remove_reference`. The first two builtins speed up builds by around 3x while 
the last builtin only sees small improvements (we may be able to optimize it 
more, though). Once added to the standard library, this should make libc++ (and 
other code) much faster to compile.

I tried to generalize as much of the builtin as possible so, the only 
functional difference between the three builtins is in the file 
`BuildUnaryTransformType`.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D67052

Files:
  clang/include/clang/AST/Type.h
  clang/include/clang/Basic/Specifiers.h
  clang/include/clang/Basic/TokenKinds.def
  clang/include/clang/Parse/Parser.h
  clang/include/clang/Sema/DeclSpec.h
  clang/lib/Format/FormatToken.cpp
  clang/lib/Lex/PPMacroExpansion.cpp
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Parse/ParseDeclCXX.cpp
  clang/lib/Sema/DeclSpec.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaTemplateVariadic.cpp
  clang/lib/Sema/SemaType.cpp
  clang/test/SemaCXX/add_reference.cpp
  libcxx/test/libcxx/utilities/meta/stress_tests/lit.site.cfg
  
libcxx/test/libcxx/utilities/meta/stress_tests/stress_test_add_lvalue_reference.sh.cpp
  
libcxx/test/libcxx/utilities/meta/stress_tests/stress_test_add_rvalue_reference.sh.cpp
  
libcxx/test/libcxx/utilities/meta/stress_tests/stress_test_remove_reference.sh.cpp

Index: libcxx/test/libcxx/utilities/meta/stress_tests/stress_test_remove_reference.sh.cpp
===================================================================
--- /dev/null
+++ libcxx/test/libcxx/utilities/meta/stress_tests/stress_test_remove_reference.sh.cpp
@@ -0,0 +1,63 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This is a dummy feature that prevents this test from running by default.
+
+// The table below compares the compile time and object size for each of the
+// variants listed in the RUN script.
+//
+//  Impl                       Compile Time      Object Size
+// ----------------------------------------------------------
+// new_remove_reference:       22.849 s          121 K
+// std::remove_reference:      25.643 s          121 K
+//
+// RUN: %cxx %flags %compile_flags -c %s -o %S/orig.o -ggdb  -ggnu-pubnames -ftemplate-depth=5000 -ftime-trace -std=c++17
+// RUN: %cxx %flags %compile_flags -c %s -o %S/new.o -ggdb  -ggnu-pubnames -ftemplate-depth=5000 -ftime-trace -std=c++17 -DTEST_NEW
+
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "template_cost_testing.h"
+
+template <int N> struct Arg { enum { value = 1 }; };
+
+#ifdef TEST_NEW
+
+template <class T>
+struct new_remove_reference
+{
+  typedef __remove_reference(T) type;
+};
+
+#define TEST_CASE_NOP()  new_remove_reference< Arg< __COUNTER__ > >{},
+#define TEST_CASE_TYPE() typename new_remove_reference< Arg< __COUNTER__ > >::type,
+
+#else
+
+#define TEST_CASE_NOP()  std::remove_reference< Arg< __COUNTER__ > >{},
+#define TEST_CASE_TYPE() typename std::remove_reference< Arg< __COUNTER__ > >::type,
+
+#endif
+
+int sink(...);
+
+int x = sink(
+  REPEAT_10000(TEST_CASE_NOP)
+  REPEAT_10000(TEST_CASE_NOP) 42
+);
+
+void Foo( REPEAT_10000(TEST_CASE_TYPE) int) { }
+
+void escape() {
+
+sink(&x);
+sink(&Foo);
+}
+
+
Index: libcxx/test/libcxx/utilities/meta/stress_tests/stress_test_add_rvalue_reference.sh.cpp
===================================================================
--- /dev/null
+++ libcxx/test/libcxx/utilities/meta/stress_tests/stress_test_add_rvalue_reference.sh.cpp
@@ -0,0 +1,63 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This is a dummy feature that prevents this test from running by default.
+
+// The table below compares the compile time and object size for each of the
+// variants listed in the RUN script.
+//
+//  Impl                       Compile Time      Object Size
+// ----------------------------------------------------------
+// new_add_rvalue_reference:   56.398 s          171 K
+// std::add_rvalue_reference:  114.59 s          271 K
+//
+// RUN: %cxx %flags %compile_flags -c %s -o %S/orig.o -ggdb  -ggnu-pubnames -ftemplate-depth=5000 -ftime-trace -std=c++17
+// RUN: %cxx %flags %compile_flags -c %s -o %S/new.o -ggdb  -ggnu-pubnames -ftemplate-depth=5000 -ftime-trace -std=c++17 -DTEST_NEW
+
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "template_cost_testing.h"
+
+template <int N> struct Arg { enum { value = 1 }; };
+
+#ifdef TEST_NEW
+
+template <class T>
+struct new_add_rvalue_reference
+{
+  typedef __add_rvalue_reference(T) type;
+};
+
+#define TEST_CASE_NOP()  new_add_rvalue_reference< Arg< __COUNTER__ > >{},
+#define TEST_CASE_TYPE() typename new_add_rvalue_reference< Arg< __COUNTER__ > >::type,
+
+#else
+
+#define TEST_CASE_NOP()  std::add_rvalue_reference< Arg< __COUNTER__ > >{},
+#define TEST_CASE_TYPE() typename std::add_rvalue_reference< Arg< __COUNTER__ > >::type,
+
+#endif
+
+int sink(...);
+
+int x = sink(
+  REPEAT_10000(TEST_CASE_NOP)
+  REPEAT_10000(TEST_CASE_NOP) 42
+);
+
+void Foo( REPEAT_10000(TEST_CASE_TYPE) int) { }
+
+void escape() {
+
+sink(&x);
+sink(&Foo);
+}
+
+
Index: libcxx/test/libcxx/utilities/meta/stress_tests/stress_test_add_lvalue_reference.sh.cpp
===================================================================
--- /dev/null
+++ libcxx/test/libcxx/utilities/meta/stress_tests/stress_test_add_lvalue_reference.sh.cpp
@@ -0,0 +1,63 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This is a dummy feature that prevents this test from running by default.
+
+// The table below compares the compile time and object size for each of the
+// variants listed in the RUN script.
+//
+//  Impl                       Compile Time      Object Size
+// ----------------------------------------------------------
+// new_add_lvalue_reference:   23,359.202 ms     171 K
+// std::add_lvalue_reference:  73,160.138 ms     201 K
+//
+// RUN: %cxx %flags %compile_flags -c %s -o %S/orig.o -ggdb  -ggnu-pubnames -ftemplate-depth=5000 -ftime-trace -std=c++17
+// RUN: %cxx %flags %compile_flags -c %s -o %S/new.o -ggdb  -ggnu-pubnames -ftemplate-depth=5000 -ftime-trace -std=c++17 -DTEST_NEW
+
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "template_cost_testing.h"
+
+template <int N> struct Arg { enum { value = 1 }; };
+
+#ifdef TEST_NEW
+
+template <class T>
+struct new_add_lvalue_reference
+{
+  typedef __add_lvalue_reference(T) type;
+};
+
+#define TEST_CASE_NOP()  new_add_lvalue_reference< Arg< __COUNTER__ > >{},
+#define TEST_CASE_TYPE() typename new_add_lvalue_reference< Arg< __COUNTER__ > >::type,
+
+#else
+
+#define TEST_CASE_NOP()  std::add_lvalue_reference< Arg< __COUNTER__ > >{},
+#define TEST_CASE_TYPE() typename std::add_lvalue_reference< Arg< __COUNTER__ > >::type,
+
+#endif
+
+int sink(...);
+
+int x = sink(
+  REPEAT_10000(TEST_CASE_NOP)
+  REPEAT_10000(TEST_CASE_NOP) 42
+);
+
+void Foo( REPEAT_10000(TEST_CASE_TYPE) int) { }
+
+void escape() {
+
+sink(&x);
+sink(&Foo);
+}
+
+
Index: libcxx/test/libcxx/utilities/meta/stress_tests/lit.site.cfg
===================================================================
--- /dev/null
+++ libcxx/test/libcxx/utilities/meta/stress_tests/lit.site.cfg
@@ -0,0 +1,2 @@
+config.cxx_under_test = "/Users/zoe/Developer/llvm-apple/mono-build/bin/clang++"
+lit_config.load_config(config, "/Users/zoe/Developer/llvm-apple/llvm-project/libcxx/test/lit.cfg")
Index: clang/test/SemaCXX/add_reference.cpp
===================================================================
--- /dev/null
+++ clang/test/SemaCXX/add_reference.cpp
@@ -0,0 +1,66 @@
+// RUN: %clang_cc1 -std=c++11 %s
+
+template<class T>
+struct test_lval_trait
+{
+  typedef __add_lvalue_reference(T) type;
+};
+
+template<class T>
+struct test_lval
+{
+  static const bool value = __is_same(typename test_lval_trait<T>::type, T&)  &&
+                            __is_same(typename test_lval_trait<T&>::type, T&) &&
+                            __is_same(typename test_lval_trait<T&&>::type, T&);
+};
+
+template<class T>
+struct test_rval_trait
+{
+  typedef __add_rvalue_reference(T) type;
+};
+
+template<class T>
+struct test_rval
+{
+  static const bool value = __is_same(typename test_rval_trait<T>::type, T&&)  &&
+                            __is_same(typename test_rval_trait<T&>::type, T&&) &&
+                            __is_same(typename test_rval_trait<T&&>::type, T&&);
+};
+
+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);
+};
+
+template<class T>
+struct test
+{
+  static const bool value = test_remove_ref<T>::value &&
+                            test_rval<T>::value &&
+                            test_lval<T>::value;
+};
+
+struct Foo { };
+
+template<class T>
+struct Bar { };
+
+template<class T>
+class Baz { };
+
+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, "");
Index: clang/lib/Sema/SemaType.cpp
===================================================================
--- clang/lib/Sema/SemaType.cpp
+++ clang/lib/Sema/SemaType.cpp
@@ -1251,6 +1251,22 @@
   return OpenCLAccessAttr::Keyword_read_only;
 }
 
+static UnaryTransformType::UTTKind
+TSTToUnaryTransformType(DeclSpec::TST SwitchTST) {
+  switch (SwitchTST) {
+  case TST_addLValueReferenceType:
+    return UnaryTransformType::AddLValueType;
+  case TST_addRValueReferenceType:
+    return UnaryTransformType::AddRValueType;
+  case TST_removeReferenceType:
+    return UnaryTransformType::RemoveReferenceType;
+  case TST_underlyingType:
+    return UnaryTransformType::EnumUnderlyingType;
+  default:
+    assert(false && "Cannot map TST to unary transform type");
+  }
+}
+
 /// Convert the specified declspec to the appropriate type
 /// object.
 /// \param state Specifies the declarator containing the declaration specifier
@@ -1593,6 +1609,20 @@
       declarator.setInvalidType(true);
     }
     break;
+  case DeclSpec::TST_addLValueReferenceType:
+  case DeclSpec::TST_addRValueReferenceType:
+  case DeclSpec::TST_removeReferenceType:
+    Result = S.GetTypeFromParser(DS.getRepAsType());
+    assert(!Result.isNull() &&
+           "Reference manipulation type transform may not have received a type.");
+    Result = S.BuildUnaryTransformType(Result,
+                                       TSTToUnaryTransformType(DS.getTypeSpecType()),
+                                       DS.getTypeSpecTypeLoc());
+    if (Result.isNull()) {
+      declarator.setInvalidType(true);
+    }
+    break;
+
 
   case DeclSpec::TST_auto:
     Result = Context.getAutoType(QualType(), AutoTypeKeyword::Auto, false);
@@ -5456,8 +5486,8 @@
       TL.setUnderlyingTInfo(TInfo);
     }
     void VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
-      // FIXME: This holds only because we only have one unary transform.
-      assert(DS.getTypeSpecType() == DeclSpec::TST_underlyingType);
+      // TODO: Should we check something like "IsUnaryTypeTransfrom(DS.getTypeSpecTypeLoc())"?
+      // assert(DS.getTypeSpecType() == DeclSpec::TST_underlyingType);
       TL.setKWLoc(DS.getTypeSpecTypeLoc());
       TL.setParensRange(DS.getTypeofParensRange());
       assert(DS.getRepAsType());
@@ -8409,6 +8439,21 @@
       return Context.getUnaryTransformType(BaseType, Underlying,
                                         UnaryTransformType::EnumUnderlyingType);
     }
+  case UnaryTransformType::AddLValueType: {
+    QualType Underlying = Context.getLValueReferenceType(BaseType.getCanonicalType());
+    return Context.getUnaryTransformType(BaseType, Underlying,
+                                         UnaryTransformType::AddLValueType);
+  }
+  case UnaryTransformType::AddRValueType: {
+    QualType Underlying = Context.getRValueReferenceType(BaseType.getCanonicalType());
+    return Context.getUnaryTransformType(BaseType, Underlying,
+                                         UnaryTransformType::AddRValueType);
+  }
+  case UnaryTransformType::RemoveReferenceType: {
+    QualType Underlying = BaseType.getNonReferenceType();
+    return Context.getUnaryTransformType(BaseType, Underlying,
+                                         UnaryTransformType::RemoveReferenceType);
+  }
   }
   llvm_unreachable("unknown unary transform type");
 }
Index: clang/lib/Sema/SemaTemplateVariadic.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateVariadic.cpp
+++ clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -838,6 +838,9 @@
   case TST_typename:
   case TST_typeofType:
   case TST_underlyingType:
+  case TST_addLValueReferenceType:
+  case TST_addRValueReferenceType:
+  case TST_removeReferenceType:
   case TST_atomic: {
     QualType T = DS.getRepAsType().get();
     if (!T.isNull() && T->containsUnexpandedParameterPack())
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -140,6 +140,9 @@
   case tok::kw_wchar_t:
   case tok::kw_bool:
   case tok::kw___underlying_type:
+  case tok::kw___add_lvalue_reference:
+  case tok::kw___add_rvalue_reference:
+  case tok::kw___remove_reference:
   case tok::kw___auto_type:
     return true;
 
@@ -5194,6 +5197,9 @@
   case DeclSpec::TST_typename:
   case DeclSpec::TST_typeofType:
   case DeclSpec::TST_underlyingType:
+  case DeclSpec::TST_addLValueReferenceType:
+  case DeclSpec::TST_addRValueReferenceType:
+  case DeclSpec::TST_removeReferenceType:
   case DeclSpec::TST_atomic: {
     // Grab the type from the parser.
     TypeSourceInfo *TSI = nullptr;
Index: clang/lib/Sema/DeclSpec.cpp
===================================================================
--- clang/lib/Sema/DeclSpec.cpp
+++ clang/lib/Sema/DeclSpec.cpp
@@ -374,6 +374,9 @@
       return false;
 
     case TST_underlyingType:
+    case TST_addLValueReferenceType:
+    case TST_addRValueReferenceType:
+    case TST_removeReferenceType:
     case TST_typename:
     case TST_typeofType: {
       QualType QT = DS.getRepAsType().get();
@@ -553,6 +556,9 @@
   case DeclSpec::TST_decltype:    return "(decltype)";
   case DeclSpec::TST_decltype_auto: return "decltype(auto)";
   case DeclSpec::TST_underlyingType: return "__underlying_type";
+  case DeclSpec::TST_addLValueReferenceType: return "__add_lvalue_reference";
+  case DeclSpec::TST_addRValueReferenceType: return "__add_rvalue_reference";
+  case DeclSpec::TST_removeReferenceType: return "__remove_reference";
   case DeclSpec::TST_unknown_anytype: return "__unknown_anytype";
   case DeclSpec::TST_atomic: return "_Atomic";
 #define GENERIC_IMAGE_TYPE(ImgType, Id) \
Index: clang/lib/Parse/ParseDeclCXX.cpp
===================================================================
--- clang/lib/Parse/ParseDeclCXX.cpp
+++ clang/lib/Parse/ParseDeclCXX.cpp
@@ -1083,6 +1083,48 @@
   DS.setTypeofParensRange(T.getRange());
 }
 
+DeclSpec::TST Parser::ReferenceTransformTokToDeclSpec() {
+  switch (Tok.getKind()) {
+  case tok::kw___add_lvalue_reference:
+    return DeclSpec::TST_addLValueReferenceType;
+  case tok::kw___add_rvalue_reference:
+    return DeclSpec::TST_addRValueReferenceType;
+  case tok::kw___remove_reference:
+    return DeclSpec::TST_removeReferenceType;
+  default:
+    assert(false && "Not a reference type specifier");
+  }
+}
+
+void Parser::ParseAddReferenceTypeSpecifier(DeclSpec &DS) {
+  DeclSpec::TST ReferenceTransformTST = ReferenceTransformTokToDeclSpec();
+
+  SourceLocation StartLoc = ConsumeToken();
+  BalancedDelimiterTracker T(*this, tok::l_paren);
+  if (T.expectAndConsume(diag::err_expected_lparen_after,
+                         "reference manipulation 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(ReferenceTransformTST,
+                         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
Index: clang/lib/Parse/ParseDecl.cpp
===================================================================
--- clang/lib/Parse/ParseDecl.cpp
+++ clang/lib/Parse/ParseDecl.cpp
@@ -3918,6 +3918,12 @@
       ParseUnderlyingTypeSpecifier(DS);
       continue;
 
+    case tok::kw___remove_reference:
+    case tok::kw___add_rvalue_reference:
+    case tok::kw___add_lvalue_reference:
+      ParseAddReferenceTypeSpecifier(DS);
+      continue;
+
     case tok::kw__Atomic:
       // C11 6.7.2.4/4:
       //   If the _Atomic keyword is immediately followed by a left parenthesis,
Index: clang/lib/Lex/PPMacroExpansion.cpp
===================================================================
--- clang/lib/Lex/PPMacroExpansion.cpp
+++ clang/lib/Lex/PPMacroExpansion.cpp
@@ -1636,6 +1636,9 @@
               .Case("__array_extent", true)
               .Case("__reference_binds_to_temporary", true)
               .Case("__underlying_type", true)
+              .Case("__add_lvalue_reference", true)
+              .Case("__add_rvalue_reference", true)
+              .Case("__remove_reference", true)
               .Default(false);
         } else {
           return llvm::StringSwitch<bool>(II->getName())
Index: clang/lib/Format/FormatToken.cpp
===================================================================
--- clang/lib/Format/FormatToken.cpp
+++ clang/lib/Format/FormatToken.cpp
@@ -55,6 +55,9 @@
   case tok::kw_wchar_t:
   case tok::kw_bool:
   case tok::kw___underlying_type:
+  case tok::kw___add_lvalue_reference:
+  case tok::kw___add_rvalue_reference:
+  case tok::kw___remove_reference:
   case tok::annot_typename:
   case tok::kw_char8_t:
   case tok::kw_char16_t:
Index: clang/include/clang/Sema/DeclSpec.h
===================================================================
--- clang/include/clang/Sema/DeclSpec.h
+++ clang/include/clang/Sema/DeclSpec.h
@@ -300,6 +300,9 @@
   static const TST TST_decltype = clang::TST_decltype;
   static const TST TST_decltype_auto = clang::TST_decltype_auto;
   static const TST TST_underlyingType = clang::TST_underlyingType;
+  static const TST TST_addLValueReferenceType = clang::TST_addLValueReferenceType;
+  static const TST TST_addRValueReferenceType = clang::TST_addRValueReferenceType;
+  static const TST TST_removeReferenceType = clang::TST_removeReferenceType;
   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;
@@ -408,7 +411,9 @@
 
   static bool isTypeRep(TST T) {
     return (T == TST_typename || T == TST_typeofType ||
-            T == TST_underlyingType || T == TST_atomic);
+            T == TST_underlyingType || T == TST_atomic||
+            T == TST_addLValueReferenceType || T == TST_addRValueReferenceType ||
+            T == TST_removeReferenceType);
   }
   static bool isExprRep(TST T) {
     return (T == TST_typeofExpr || T == TST_decltype);
Index: clang/include/clang/Parse/Parser.h
===================================================================
--- clang/include/clang/Parse/Parser.h
+++ clang/include/clang/Parse/Parser.h
@@ -2602,6 +2602,8 @@
                                          SourceLocation StartLoc,
                                          SourceLocation EndLoc);
   void ParseUnderlyingTypeSpecifier(DeclSpec &DS);
+  DeclSpec::TST ReferenceTransformTokToDeclSpec();
+  void ParseAddReferenceTypeSpecifier(DeclSpec &DS);
   void ParseAtomicSpecifier(DeclSpec &DS);
 
   ExprResult ParseAlignArgument(SourceLocation Start,
Index: clang/include/clang/Basic/TokenKinds.def
===================================================================
--- clang/include/clang/Basic/TokenKinds.def
+++ clang/include/clang/Basic/TokenKinds.def
@@ -485,7 +485,10 @@
 TYPE_TRAIT_1(__is_union, IsUnion, KEYCXX)
 TYPE_TRAIT_1(__has_unique_object_representations,
              HasUniqueObjectRepresentations, KEYCXX)
-KEYWORD(__underlying_type           , KEYCXX)
+KEYWORD(__underlying_type                  , KEYCXX)
+KEYWORD(__add_lvalue_reference             , KEYCXX)
+KEYWORD(__add_rvalue_reference             , KEYCXX)
+KEYWORD(__remove_reference                 , KEYCXX)
 
 // Clang-only C++ Type Traits
 TYPE_TRAIT_2(__reference_binds_to_temporary, ReferenceBindsToTemporary, KEYCXX)
Index: clang/include/clang/Basic/Specifiers.h
===================================================================
--- clang/include/clang/Basic/Specifiers.h
+++ clang/include/clang/Basic/Specifiers.h
@@ -87,6 +87,9 @@
     TST_typeofExpr,
     TST_decltype,         // C++11 decltype
     TST_underlyingType,   // __underlying_type for C++11
+    TST_addLValueReferenceType, // __add_lvalue_reference
+    TST_addRValueReferenceType, // __add_rvalue_reference
+    TST_removeReferenceType, // __remove_reference
     TST_auto,             // C++11 auto
     TST_decltype_auto,    // C++1y decltype(auto)
     TST_auto_type,        // __auto_type extension
Index: clang/include/clang/AST/Type.h
===================================================================
--- clang/include/clang/AST/Type.h
+++ clang/include/clang/AST/Type.h
@@ -4348,7 +4348,10 @@
 class UnaryTransformType : public Type {
 public:
   enum UTTKind {
-    EnumUnderlyingType
+    EnumUnderlyingType,
+    RemoveReferenceType,
+    AddRValueType,
+    AddLValueType
   };
 
 private:
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to