zoecarver updated this revision to Diff 220226.
zoecarver added a comment.

- diff from D67052 <https://reviews.llvm.org/D67052>, not master


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D67588/new/

https://reviews.llvm.org/D67588

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_cv.cpp
  clang/test/SemaCXX/add_reference.cpp
  libcxx/test/libcxx/utilities/meta/stress_tests/stress_test_add_cv.sh.cpp
  
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_cv.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_remove_cv.sh.cpp
===================================================================
--- /dev/null
+++ libcxx/test/libcxx/utilities/meta/stress_tests/stress_test_remove_cv.sh.cpp
@@ -0,0 +1,62 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_cv:       23.594 s          121 K
+// std::remove_cv:      38.817 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 "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_cv
+{
+  typedef __remove_cv(T) type;
+};
+
+#define TEST_CASE_NOP()  new_remove_cv< Arg< __COUNTER__ > >{},
+#define TEST_CASE_TYPE() typename new_remove_cv< Arg< __COUNTER__ > >::type,
+
+#else
+
+#define TEST_CASE_NOP()  std::remove_cv< Arg< __COUNTER__ > >{},
+#define TEST_CASE_TYPE() typename std::remove_cv< 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/stress_test_add_cv.sh.cpp
===================================================================
--- /dev/null
+++ libcxx/test/libcxx/utilities/meta/stress_tests/stress_test_add_cv.sh.cpp
@@ -0,0 +1,62 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_cv:       22.710 s          121 K
+// std::add_cv:      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 "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_cv
+{
+  typedef __add_cv(T) type;
+};
+
+#define TEST_CASE_NOP()  new_add_cv< Arg< __COUNTER__ > >{},
+#define TEST_CASE_TYPE() typename new_add_cv< Arg< __COUNTER__ > >::type,
+
+#else
+
+#define TEST_CASE_NOP()  std::add_cv< Arg< __COUNTER__ > >{},
+#define TEST_CASE_TYPE() typename std::add_cv< 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: 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/test/SemaCXX/add_cv.cpp
===================================================================
--- /dev/null
+++ clang/test/SemaCXX/add_cv.cpp
@@ -0,0 +1,83 @@
+// 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 add_const
+{
+  typedef __add_const(T) type;
+};
+
+template<class T>
+struct add_volatile
+{
+  typedef __add_volatile(T) type;
+};
+
+template<class T>
+struct add_cv
+{
+  typedef __add_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) &&
+
+    __is_same(typename add_const<const T>::type, const T) &&
+    __is_same(typename add_const<volatile T>::type, const volatile T) &&
+    __is_same(typename add_const<T>::type, const T) &&
+
+    __is_same(typename add_volatile<volatile T>::type, volatile T) &&
+    __is_same(typename add_volatile<const T>::type, const volatile T) &&
+    __is_same(typename add_volatile<T>::type, volatile T) &&
+
+    __is_same(typename add_cv<T>::type, const volatile T) &&
+    __is_same(typename add_cv<const volatile T>::type, const volatile T) &&
+    __is_same(typename add_cv<const T>::type, const volatile T) &&
+    __is_same(typename add_cv<volatile T>::type, const volatile T);
+};
+
+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,34 @@
   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;
+  case TST_removeCV:
+    return UnaryTransformType::RemoveCV;
+  case TST_removeConst:
+    return UnaryTransformType::RemoveConst;
+  case TST_removeVolatile:
+    return UnaryTransformType::RemoveVolatile;
+  case TST_addCV:
+    return UnaryTransformType::AddCV;
+  case TST_addConst:
+    return UnaryTransformType::AddConst;
+  case TST_addVolatile:
+    return UnaryTransformType::AddVolatile;
+  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 +1621,26 @@
       declarator.setInvalidType(true);
     }
     break;
+  case DeclSpec::TST_addLValueReferenceType:
+  case DeclSpec::TST_addRValueReferenceType:
+  case DeclSpec::TST_removeReferenceType:
+  case DeclSpec::TST_removeCV:
+  case DeclSpec::TST_removeConst:
+  case DeclSpec::TST_removeVolatile:
+  case DeclSpec::TST_addCV:
+  case DeclSpec::TST_addConst:
+  case DeclSpec::TST_addVolatile:
+    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);
@@ -5461,8 +5509,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());
@@ -8384,6 +8432,61 @@
       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);
+  }
+  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);
+  }
+  case UnaryTransformType::AddCV: {
+    QualType Underlying = BaseType.withConst().withVolatile();
+    return Context.getUnaryTransformType(BaseType, Underlying,
+                                         UnaryTransformType::AddCV);
+  }
+  case UnaryTransformType::AddConst: {
+    QualType Underlying = BaseType.withConst();
+    return Context.getUnaryTransformType(BaseType, Underlying,
+                                         UnaryTransformType::AddConst);
+  }
+  case UnaryTransformType::AddVolatile: {
+    QualType Underlying = BaseType.withVolatile();
+    return Context.getUnaryTransformType(BaseType, Underlying,
+                                         UnaryTransformType::AddVolatile);
+  }
   }
   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,15 @@
   case TST_typename:
   case TST_typeofType:
   case TST_underlyingType:
+  case TST_addLValueReferenceType:
+  case TST_addRValueReferenceType:
+  case TST_removeReferenceType:
+  case TST_removeCV:
+  case TST_removeConst:
+  case TST_removeVolatile:
+  case TST_addCV:
+  case TST_addConst:
+  case TST_addVolatile:
   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
@@ -141,6 +141,15 @@
   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___remove_cv:
+  case tok::kw___remove_const:
+  case tok::kw___remove_volatile:
+  case tok::kw___add_cv:
+  case tok::kw___add_const:
+  case tok::kw___add_volatile:
   case tok::kw___auto_type:
     return true;
 
@@ -5284,6 +5293,15 @@
   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_removeCV:
+  case DeclSpec::TST_removeConst:
+  case DeclSpec::TST_removeVolatile:
+  case DeclSpec::TST_addCV:
+  case DeclSpec::TST_addConst:
+  case DeclSpec::TST_addVolatile:
   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,15 @@
       return false;
 
     case TST_underlyingType:
+    case TST_addLValueReferenceType:
+    case TST_addRValueReferenceType:
+    case TST_removeReferenceType:
+    case TST_removeCV:
+    case TST_removeConst:
+    case TST_removeVolatile:
+    case TST_addCV:
+    case TST_addConst:
+    case TST_addVolatile:
     case TST_typename:
     case TST_typeofType: {
       QualType QT = DS.getRepAsType().get();
@@ -553,6 +562,15 @@
   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_removeCV: return "__remove_cv";
+  case DeclSpec::TST_removeConst: return "__remove_const";
+  case DeclSpec::TST_removeVolatile: return "__remove_volatile";
+  case DeclSpec::TST_addCV: return "__add_cv";
+  case DeclSpec::TST_addConst: return "__add_const";
+  case DeclSpec::TST_addVolatile: return "__add_volatile";
   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,60 @@
   DS.setTypeofParensRange(T.getRange());
 }
 
+DeclSpec::TST Parser::TypeTransformTokToDeclSpec() {
+  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;
+  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;
+  case tok::kw___add_cv:
+    return DeclSpec::TST_addCV;
+  case tok::kw___add_const:
+    return DeclSpec::TST_addConst;
+  case tok::kw___add_volatile:
+    return DeclSpec::TST_addVolatile;
+  default:
+    assert(false && "Not a reference type specifier");
+  }
+}
+
+void Parser::ParseTypeTransformTypeSpecifier(DeclSpec &DS) {
+  DeclSpec::TST TypeTransformTST = TypeTransformTokToDeclSpec();
+
+  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(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
Index: clang/lib/Parse/ParseDecl.cpp
===================================================================
--- clang/lib/Parse/ParseDecl.cpp
+++ clang/lib/Parse/ParseDecl.cpp
@@ -3919,6 +3919,18 @@
       ParseUnderlyingTypeSpecifier(DS);
       continue;
 
+    case tok::kw___remove_reference:
+    case tok::kw___add_rvalue_reference:
+    case tok::kw___add_lvalue_reference:
+    case tok::kw___remove_cv:
+    case tok::kw___remove_const:
+    case tok::kw___remove_volatile:
+    case tok::kw___add_cv:
+    case tok::kw___add_const:
+    case tok::kw___add_volatile:
+      ParseTypeTransformTypeSpecifier(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,15 @@
               .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)
+              .Case("__remove_cv", true)
+              .Case("__remove_const", true)
+              .Case("__remove_volatile", true)
+              .Case("__add_cv", true)
+              .Case("__add_const", true)
+              .Case("__add_volatile", 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,15 @@
   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___remove_cv:
+  case tok::kw___remove_const:
+  case tok::kw___remove_volatile:
+  case tok::kw___add_cv:
+  case tok::kw___add_const:
+  case tok::kw___add_volatile:
   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,15 @@
   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_removeCV = clang::TST_removeCV;
+  static const TST TST_removeConst = clang::TST_removeConst;
+  static const TST TST_removeVolatile = clang::TST_removeVolatile;
+  static const TST TST_addCV = clang::TST_addCV;
+  static const TST TST_addConst = clang::TST_addConst;
+  static const TST TST_addVolatile = clang::TST_addVolatile;
   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 +417,11 @@
 
   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 ||
+            T == TST_removeCV || T == TST_removeConst || T == TST_removeVolatile ||
+            T == TST_addCV || T == TST_addConst || T == TST_addVolatile);
   }
   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 TypeTransformTokToDeclSpec();
+  void ParseTypeTransformTypeSpecifier(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
@@ -486,7 +486,16 @@
 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)
+KEYWORD(__remove_cv                        , KEYCXX)
+KEYWORD(__remove_const                     , KEYCXX)
+KEYWORD(__remove_volatile                  , KEYCXX)
+KEYWORD(__add_cv                           , KEYCXX)
+KEYWORD(__add_const                        , KEYCXX)
+KEYWORD(__add_volatile                     , 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
@@ -88,6 +88,15 @@
     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_removeCV, // __remove_cv
+    TST_removeConst, // __remove_const
+    TST_removeVolatile, // __remove_volatile
+    TST_addCV, // __add_cv
+    TST_addConst, // __add_const
+    TST_addVolatile, // __add_volatile
     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
@@ -4363,7 +4363,16 @@
 class UnaryTransformType : public Type {
 public:
   enum UTTKind {
-    EnumUnderlyingType
+    EnumUnderlyingType,
+    RemoveReferenceType,
+    AddRValueType,
+    AddLValueType,
+    RemoveCV,
+    RemoveConst,
+    RemoveVolatile,
+    AddCV,
+    AddConst,
+    AddVolatile
   };
 
 private:
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to