cjdb updated this revision to Diff 396248.
cjdb edited the summary of this revision.
cjdb added a comment.

adds more type traits


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D116203

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/AST/ASTContext.cpp
  clang/lib/AST/ItaniumMangle.cpp
  clang/lib/AST/JSONNodeDumper.cpp
  clang/lib/AST/TextNodeDumper.cpp
  clang/lib/AST/TypePrinter.cpp
  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/type-traits.cpp

Index: clang/test/SemaCXX/type-traits.cpp
===================================================================
--- clang/test/SemaCXX/type-traits.cpp
+++ clang/test/SemaCXX/type-traits.cpp
@@ -2854,3 +2854,552 @@
 #undef T16384
 #undef T32768
 } // namespace type_trait_expr_numargs_overflow
+
+struct S {};
+void check_add_const() {
+  { int a[T(__is_same(__add_const(void), const void))]; }
+  { int a[T(__is_same(__add_const(int), const int))]; }
+  { int a[T(__is_same(__add_const(const int), const int))]; }
+  { int a[T(__is_same(__add_const(volatile int), const volatile int))]; }
+  { int a[T(__is_same(__add_const(const volatile int), const volatile int))]; }
+  { int a[T(__is_same(__add_const(int*), int* const))]; }
+  { int a[T(__is_same(__add_const(int&), int&))]; }
+  { int a[T(__is_same(__add_const(int&&), int&&))]; }
+  { int a[T(__is_same(__add_const(int()), int()))]; }
+  { int a[T(__is_same(__add_const(int(*)()), int(* const)()))]; }
+  { int a[T(__is_same(__add_const(int(&)()), int(&)()))]; }
+
+  { int a[T(__is_same(__add_const(S), const S))]; }
+  { int a[T(__is_same(__add_const(const S), const S))]; }
+  { int a[T(__is_same(__add_const(volatile S), const volatile S))]; }
+  { int a[T(__is_same(__add_const(const volatile S), const volatile S))]; }
+  { int a[T(__is_same(__add_const(int S::*), int S::* const))]; }
+  { int a[T(__is_same(__add_const(int (S::*)()), int (S::* const)()))]; }
+  { int a[T(__is_same(__add_const(int (S::*)() &), int (S::* const)() &))]; }
+  { int a[T(__is_same(__add_const(int (S::*)() &&), int (S::* const)() &&))]; }
+  { int a[T(__is_same(__add_const(int (S::*)() const), int (S::* const)() const))]; }
+  { int a[T(__is_same(__add_const(int (S::*)() const&), int (S::* const)() const&))]; }
+  { int a[T(__is_same(__add_const(int (S::*)() const&&), int (S::* const)() const&&))]; }
+  { int a[T(__is_same(__add_const(int (S::*)() volatile), int (S::* const)() volatile))]; }
+  { int a[T(__is_same(__add_const(int (S::*)() volatile&), int (S::* const)() volatile&))]; }
+  { int a[T(__is_same(__add_const(int (S::*)() volatile&&), int (S::* const)() volatile&&))]; }
+  { int a[T(__is_same(__add_const(int (S::*)() const volatile), int (S::* const)() const volatile))]; }
+  { int a[T(__is_same(__add_const(int (S::*)() const volatile&), int (S::* const)() const volatile&))]; }
+  { int a[T(__is_same(__add_const(int (S::*)() const volatile&&), int (S::* const)() const volatile&&))]; }
+}
+
+void check_remove_const() {
+  { int a[T(__is_same(__remove_const(void), void))]; }
+  { int a[T(__is_same(__remove_const(const void), void))]; }
+  { int a[T(__is_same(__remove_const(int), int))]; }
+  { int a[T(__is_same(__remove_const(const int), int))]; }
+  { int a[T(__is_same(__remove_const(volatile int), volatile int))]; }
+  { int a[T(__is_same(__remove_const(const volatile int), volatile int))]; }
+  { int a[T(__is_same(__remove_const(int*), int*))]; }
+  { int a[T(__is_same(__remove_const(int* const), int*))]; }
+  { int a[T(__is_same(__remove_const(int const* const), int const*))]; }
+  { int a[T(__is_same(__remove_const(int&), int&))]; }
+  { int a[T(__is_same(__remove_const(int const&), int const&))]; }
+  { int a[T(__is_same(__remove_const(int&&), int&&))]; }
+  { int a[T(__is_same(__remove_const(int const&&), int const&&))]; }
+  { int a[T(__is_same(__remove_const(int()), int()))]; }
+  { int a[T(__is_same(__remove_const(int(* const)()), int(*)()))]; }
+  { int a[T(__is_same(__remove_const(int(&)()), int(&)()))]; }
+
+  { int a[T(__is_same(__remove_const(S), S))]; }
+  { int a[T(__is_same(__remove_const(const S),  S))]; }
+  { int a[T(__is_same(__remove_const(volatile S), volatile S))]; }
+  { int a[T(__is_same(__remove_const(const volatile S), volatile S))]; }
+  { int a[T(__is_same(__remove_const(int S::* const), int S::*))]; }
+  { int a[T(__is_same(__remove_const(int (S::* const)()), int (S::*)()))]; }
+  { int a[T(__is_same(__remove_const(int (S::* const)() &), int (S::*)() &))]; }
+  { int a[T(__is_same(__remove_const(int (S::* const)() &&), int (S::*)() &&))]; }
+  { int a[T(__is_same(__remove_const(int (S::* const)() const), int (S::*)() const))]; }
+  { int a[T(__is_same(__remove_const(int (S::* const)() const&), int (S::*)() const&))]; }
+  { int a[T(__is_same(__remove_const(int (S::* const)() const&&), int (S::*)() const&&))]; }
+  { int a[T(__is_same(__remove_const(int (S::* const)() volatile), int (S::*)() volatile))]; }
+  { int a[T(__is_same(__remove_const(int (S::* const)() volatile&), int (S::*)() volatile&))]; }
+  { int a[T(__is_same(__remove_const(int (S::* const)() volatile&&), int (S::*)() volatile&&))]; }
+  { int a[T(__is_same(__remove_const(int (S::* const)() const volatile), int (S::*)() const volatile))]; }
+  { int a[T(__is_same(__remove_const(int (S::* const)() const volatile&), int (S::*)() const volatile&))]; }
+  { int a[T(__is_same(__remove_const(int (S::* const)() const volatile&&), int (S::*)() const volatile&&))]; }
+}
+
+void check_add_volatile() {
+  { int a[T(__is_same(__add_volatile(void), volatile void))]; }
+  { int a[T(__is_same(__add_volatile(int), volatile int))]; }
+  { int a[T(__is_same(__add_volatile(const int), const volatile int))]; }
+  { int a[T(__is_same(__add_volatile(volatile int), volatile int))]; }
+  { int a[T(__is_same(__add_volatile(const volatile int), const volatile int))]; }
+  { int a[T(__is_same(__add_volatile(int*), int* volatile))]; }
+  { int a[T(__is_same(__add_volatile(int&), int&))]; }
+  { int a[T(__is_same(__add_volatile(int&&), int&&))]; }
+  { int a[T(__is_same(__add_volatile(int()), int()))]; }
+  { int a[T(__is_same(__add_volatile(int(*)()), int(* volatile)()))]; }
+  { int a[T(__is_same(__add_volatile(int(&)()), int(&)()))]; }
+
+  { int a[T(__is_same(__add_volatile(S), volatile S))]; }
+  { int a[T(__is_same(__add_volatile(const S), const volatile S))]; }
+  { int a[T(__is_same(__add_volatile(volatile S), volatile S))]; }
+  { int a[T(__is_same(__add_volatile(const volatile S), const volatile S))]; }
+  { int a[T(__is_same(__add_volatile(int S::*), int S::* volatile))]; }
+  { int a[T(__is_same(__add_volatile(int (S::*)()), int (S::* volatile)()))]; }
+  { int a[T(__is_same(__add_volatile(int (S::*)() &), int (S::* volatile)() &))]; }
+  { int a[T(__is_same(__add_volatile(int (S::*)() &&), int (S::* volatile)() &&))]; }
+  { int a[T(__is_same(__add_volatile(int (S::*)() const), int (S::* volatile)() const))]; }
+  { int a[T(__is_same(__add_volatile(int (S::*)() const&), int (S::* volatile)() const&))]; }
+  { int a[T(__is_same(__add_volatile(int (S::*)() const&&), int (S::* volatile)() const&&))]; }
+  { int a[T(__is_same(__add_volatile(int (S::*)() volatile), int (S::* volatile)() volatile))]; }
+  { int a[T(__is_same(__add_volatile(int (S::*)() volatile&), int (S::* volatile)() volatile&))]; }
+  { int a[T(__is_same(__add_volatile(int (S::*)() volatile&&), int (S::* volatile)() volatile&&))]; }
+  { int a[T(__is_same(__add_volatile(int (S::*)() const volatile), int (S::* volatile)() const volatile))]; }
+  { int a[T(__is_same(__add_volatile(int (S::*)() const volatile&), int (S::* volatile)() const volatile&))]; }
+  { int a[T(__is_same(__add_volatile(int (S::*)() const volatile&&), int (S::* volatile)() const volatile&&))]; }
+}
+
+void check_remove_volatile() {
+  { int a[T(__is_same(__remove_volatile(void), void))]; }
+  { int a[T(__is_same(__remove_volatile(volatile void), void))]; }
+  { int a[T(__is_same(__remove_volatile(int), int))]; }
+  { int a[T(__is_same(__remove_volatile(const int), const int))]; }
+  { int a[T(__is_same(__remove_volatile(volatile int), int))]; }
+  { int a[T(__is_same(__remove_volatile(const volatile int), const int))]; }
+  { int a[T(__is_same(__remove_volatile(int*), int*))]; }
+  { int a[T(__is_same(__remove_volatile(int* volatile), int*))]; }
+  { int a[T(__is_same(__remove_volatile(int volatile* volatile), int volatile*))]; }
+  { int a[T(__is_same(__remove_volatile(int&), int&))]; }
+  { int a[T(__is_same(__remove_volatile(int volatile&), int volatile&))]; }
+  { int a[T(__is_same(__remove_volatile(int&&), int&&))]; }
+  { int a[T(__is_same(__remove_volatile(int volatile&&), int volatile&&))]; }
+  { int a[T(__is_same(__remove_volatile(int()), int()))]; }
+  { int a[T(__is_same(__remove_volatile(int(* volatile)()), int(*)()))]; }
+  { int a[T(__is_same(__remove_volatile(int(&)()), int(&)()))]; }
+
+  { int a[T(__is_same(__remove_volatile(S), S))]; }
+  { int a[T(__is_same(__remove_volatile(const S), const  S))]; }
+  { int a[T(__is_same(__remove_volatile(volatile S), S))]; }
+  { int a[T(__is_same(__remove_volatile(const volatile S), const S))]; }
+  { int a[T(__is_same(__remove_volatile(int S::* volatile), int S::*))]; }
+  { int a[T(__is_same(__remove_volatile(int (S::* volatile)()), int (S::*)()))]; }
+  { int a[T(__is_same(__remove_volatile(int (S::* volatile)() &), int (S::*)() &))]; }
+  { int a[T(__is_same(__remove_volatile(int (S::* volatile)() &&), int (S::*)() &&))]; }
+  { int a[T(__is_same(__remove_volatile(int (S::* volatile)() const), int (S::*)() const))]; }
+  { int a[T(__is_same(__remove_volatile(int (S::* volatile)() const&), int (S::*)() const&))]; }
+  { int a[T(__is_same(__remove_volatile(int (S::* volatile)() const&&), int (S::*)() const&&))]; }
+  { int a[T(__is_same(__remove_volatile(int (S::* volatile)() volatile), int (S::*)() volatile))]; }
+  { int a[T(__is_same(__remove_volatile(int (S::* volatile)() volatile&), int (S::*)() volatile&))]; }
+  { int a[T(__is_same(__remove_volatile(int (S::* volatile)() volatile&&), int (S::*)() volatile&&))]; }
+  { int a[T(__is_same(__remove_volatile(int (S::* volatile)() const volatile), int (S::*)() const volatile))]; }
+  { int a[T(__is_same(__remove_volatile(int (S::* volatile)() const volatile&), int (S::*)() const volatile&))]; }
+  { int a[T(__is_same(__remove_volatile(int (S::* volatile)() const volatile&&), int (S::*)() const volatile&&))]; }
+}
+
+void check_add_cv() {
+  { int a[T(__is_same(__add_cv(void), const volatile void))]; }
+  { int a[T(__is_same(__add_cv(int), const volatile int))]; }
+  { int a[T(__is_same(__add_cv(const int), const volatile int))]; }
+  { int a[T(__is_same(__add_cv(volatile int), const volatile int))]; }
+  { int a[T(__is_same(__add_cv(const volatile int), const volatile int))]; }
+  { int a[T(__is_same(__add_cv(int*), int* const volatile))]; }
+  { int a[T(__is_same(__add_cv(int&), int&))]; }
+  { int a[T(__is_same(__add_cv(int&&), int&&))]; }
+  { int a[T(__is_same(__add_cv(int()), int()))]; }
+  { int a[T(__is_same(__add_cv(int(*)()), int(* const volatile)()))]; }
+  { int a[T(__is_same(__add_cv(int(&)()), int(&)()))]; }
+
+  { int a[T(__is_same(__add_cv(S), const volatile S))]; }
+  { int a[T(__is_same(__add_cv(const S), const volatile S))]; }
+  { int a[T(__is_same(__add_cv(volatile S), const volatile S))]; }
+  { int a[T(__is_same(__add_cv(const volatile S), const volatile S))]; }
+  { int a[T(__is_same(__add_cv(int S::*), int S::* const volatile))]; }
+  { int a[T(__is_same(__add_cv(int (S::*)()), int (S::* const volatile)()))]; }
+  { int a[T(__is_same(__add_cv(int (S::*)() &), int (S::* const volatile)() &))]; }
+  { int a[T(__is_same(__add_cv(int (S::*)() &&), int (S::* const volatile)() &&))]; }
+  { int a[T(__is_same(__add_cv(int (S::*)() const), int (S::* const volatile)() const))]; }
+  { int a[T(__is_same(__add_cv(int (S::*)() const&), int (S::* const volatile)() const&))]; }
+  { int a[T(__is_same(__add_cv(int (S::*)() const&&), int (S::* const volatile)() const&&))]; }
+  { int a[T(__is_same(__add_cv(int (S::*)() volatile), int (S::* const volatile)() volatile))]; }
+  { int a[T(__is_same(__add_cv(int (S::*)() volatile&), int (S::* const volatile)() volatile&))]; }
+  { int a[T(__is_same(__add_cv(int (S::*)() volatile&&), int (S::* const volatile)() volatile&&))]; }
+  { int a[T(__is_same(__add_cv(int (S::*)() const volatile), int (S::* const volatile)() const volatile))]; }
+  { int a[T(__is_same(__add_cv(int (S::*)() const volatile&), int (S::* const volatile)() const volatile&))]; }
+  { int a[T(__is_same(__add_cv(int (S::*)() const volatile&&), int (S::* const volatile)() const volatile&&))]; }
+}
+
+void check_remove_cv() {
+  { int a[T(__is_same(__remove_cv(void), void))]; }
+  { int a[T(__is_same(__remove_cv(const volatile void), void))]; }
+  { int a[T(__is_same(__remove_cv(int), int))]; }
+  { int a[T(__is_same(__remove_cv(const int), int))]; }
+  { int a[T(__is_same(__remove_cv(volatile int), int))]; }
+  { int a[T(__is_same(__remove_cv(const volatile int), int))]; }
+  { int a[T(__is_same(__remove_cv(int*), int*))]; }
+  { int a[T(__is_same(__remove_cv(int* const volatile), int*))]; }
+  { int a[T(__is_same(__remove_cv(int const* const volatile), int const*))]; }
+  { int a[T(__is_same(__remove_cv(int&), int&))]; }
+  { int a[T(__is_same(__remove_cv(int const volatile&), int const volatile&))]; }
+  { int a[T(__is_same(__remove_cv(int&&), int&&))]; }
+  { int a[T(__is_same(__remove_cv(int const volatile&&), int const volatile&&))]; }
+  { int a[T(__is_same(__remove_cv(int()), int()))]; }
+  { int a[T(__is_same(__remove_cv(int(* const volatile)()), int(*)()))]; }
+  { int a[T(__is_same(__remove_cv(int(&)()), int(&)()))]; }
+
+  { int a[T(__is_same(__remove_cv(S), S))]; }
+  { int a[T(__is_same(__remove_cv(const S), S))]; }
+  { int a[T(__is_same(__remove_cv(volatile S), S))]; }
+  { int a[T(__is_same(__remove_cv(const volatile S), S))]; }
+  { int a[T(__is_same(__remove_cv(int S::* const volatile), int S::*))]; }
+  { int a[T(__is_same(__remove_cv(int (S::* const volatile)()), int (S::*)()))]; }
+  { int a[T(__is_same(__remove_cv(int (S::* const volatile)() &), int (S::*)() &))]; }
+  { int a[T(__is_same(__remove_cv(int (S::* const volatile)() &&), int (S::*)() &&))]; }
+  { int a[T(__is_same(__remove_cv(int (S::* const volatile)() const), int (S::*)() const))]; }
+  { int a[T(__is_same(__remove_cv(int (S::* const volatile)() const&), int (S::*)() const&))]; }
+  { int a[T(__is_same(__remove_cv(int (S::* const volatile)() const&&), int (S::*)() const&&))]; }
+  { int a[T(__is_same(__remove_cv(int (S::* const volatile)() volatile), int (S::*)() volatile))]; }
+  { int a[T(__is_same(__remove_cv(int (S::* const volatile)() volatile&), int (S::*)() volatile&))]; }
+  { int a[T(__is_same(__remove_cv(int (S::* const volatile)() volatile&&), int (S::*)() volatile&&))]; }
+  { int a[T(__is_same(__remove_cv(int (S::* const volatile)() const volatile), int (S::*)() const volatile))]; }
+  { int a[T(__is_same(__remove_cv(int (S::* const volatile)() const volatile&), int (S::*)() const volatile&))]; }
+  { int a[T(__is_same(__remove_cv(int (S::* const volatile)() const volatile&&), int (S::*)() const volatile&&))]; }
+}
+
+void add_pointer() {
+  { int a[T(__is_same(__add_pointer(void), void*))]; }
+  { int a[T(__is_same(__add_pointer(const void), const void*))]; }
+  { int a[T(__is_same(__add_pointer(volatile void), volatile void*))]; }
+  { int a[T(__is_same(__add_pointer(const volatile void), const volatile void*))]; }
+  { int a[T(__is_same(__add_pointer(int), int*))]; }
+  { int a[T(__is_same(__add_pointer(const int), const int*))]; }
+  { int a[T(__is_same(__add_pointer(volatile int), volatile int*))]; }
+  { int a[T(__is_same(__add_pointer(const volatile int), const volatile int*))]; }
+  { int a[T(__is_same(__add_pointer(int*), int**))]; }
+  { int a[T(__is_same(__add_pointer(int&), int*))]; }
+  { int a[T(__is_same(__add_pointer(int&&), int*))]; }
+  { int a[T(__is_same(__add_pointer(int()), int(*)()))]; }
+  { int a[T(__is_same(__add_pointer(int(*)()), int(**)()))]; }
+  { int a[T(__is_same(__add_pointer(int(&)()), int(*)()))]; }
+
+  { int a[T(__is_same(__add_pointer(S), S*))]; }
+  { int a[T(__is_same(__add_pointer(const S), const S*))]; }
+  { int a[T(__is_same(__add_pointer(volatile S), volatile S*))]; }
+  { int a[T(__is_same(__add_pointer(const volatile S), const volatile S*))]; }
+  { int a[T(__is_same(__add_pointer(int S::*), int S::**))]; }
+  { int a[T(__is_same(__add_pointer(int (S::*)()), int (S::**)()))]; }
+  { int a[T(__is_same(__add_pointer(int (S::*)() &), int (S::**)() &))]; }
+  { int a[T(__is_same(__add_pointer(int (S::*)() &&), int (S::**)() &&))]; }
+  { int a[T(__is_same(__add_pointer(int (S::*)() const), int (S::**)() const))]; }
+  { int a[T(__is_same(__add_pointer(int (S::*)() const&), int (S::**)() const&))]; }
+  { int a[T(__is_same(__add_pointer(int (S::*)() const&&), int (S::**)() const&&))]; }
+  { int a[T(__is_same(__add_pointer(int (S::*)() volatile), int (S::**)() volatile))]; }
+  { int a[T(__is_same(__add_pointer(int (S::*)() volatile&), int (S::**)() volatile&))]; }
+  { int a[T(__is_same(__add_pointer(int (S::*)() volatile&&), int (S::**)() volatile&&))]; }
+  { int a[T(__is_same(__add_pointer(int (S::*)() const volatile), int (S::**)() const volatile))]; }
+  { int a[T(__is_same(__add_pointer(int (S::*)() const volatile&), int (S::**)() const volatile&))]; }
+  { int a[T(__is_same(__add_pointer(int (S::*)() const volatile&&), int (S::**)() const volatile&&))]; }
+}
+
+void add_lvalue_reference() {
+  { int a[T(__is_same(__add_lvalue_reference(void), void))]; }
+  { int a[T(__is_same(__add_lvalue_reference(const void), const void))]; }
+  { int a[T(__is_same(__add_lvalue_reference(volatile void), volatile void))]; }
+  { int a[T(__is_same(__add_lvalue_reference(const volatile void), const volatile void))]; }
+  { int a[T(__is_same(__add_lvalue_reference(int), int&))]; }
+  { int a[T(__is_same(__add_lvalue_reference(const int), const int&))]; }
+  { int a[T(__is_same(__add_lvalue_reference(volatile int), volatile int&))]; }
+  { int a[T(__is_same(__add_lvalue_reference(const volatile int), const volatile int&))]; }
+  { int a[T(__is_same(__add_lvalue_reference(int*), int*&))]; }
+  { int a[T(__is_same(__add_lvalue_reference(int&), int&))]; }
+  { int a[T(__is_same(__add_lvalue_reference(int&&), int&))]; } // reference collapsing
+  { int a[T(__is_same(__add_lvalue_reference(int()), int(&)()))]; }
+  { int a[T(__is_same(__add_lvalue_reference(int(*)()), int(*&)()))]; }
+  { int a[T(__is_same(__add_lvalue_reference(int(&)()), int(&)()))]; }
+
+  { int a[T(__is_same(__add_lvalue_reference(S), S&))]; }
+  { int a[T(__is_same(__add_lvalue_reference(const S), const S&))]; }
+  { int a[T(__is_same(__add_lvalue_reference(volatile S), volatile S&))]; }
+  { int a[T(__is_same(__add_lvalue_reference(const volatile S), const volatile S&))]; }
+  { int a[T(__is_same(__add_lvalue_reference(int S::*), int S::*&))]; }
+  { int a[T(__is_same(__add_lvalue_reference(int (S::*)()), int (S::*&)()))]; }
+  { int a[T(__is_same(__add_lvalue_reference(int (S::*)() &), int (S::*&)() &))]; }
+  { int a[T(__is_same(__add_lvalue_reference(int (S::*)() &&), int (S::*&)() &&))]; }
+  { int a[T(__is_same(__add_lvalue_reference(int (S::*)() const), int (S::*&)() const))]; }
+  { int a[T(__is_same(__add_lvalue_reference(int (S::*)() const&), int (S::*&)() const&))]; }
+  { int a[T(__is_same(__add_lvalue_reference(int (S::*)() const&&), int (S::*&)() const&&))]; }
+  { int a[T(__is_same(__add_lvalue_reference(int (S::*)() volatile), int (S::*&)() volatile))]; }
+  { int a[T(__is_same(__add_lvalue_reference(int (S::*)() volatile&), int (S::*&)() volatile&))]; }
+  { int a[T(__is_same(__add_lvalue_reference(int (S::*)() volatile&&), int (S::*&)() volatile&&))]; }
+  { int a[T(__is_same(__add_lvalue_reference(int (S::*)() const volatile), int (S::*&)() const volatile))]; }
+  { int a[T(__is_same(__add_lvalue_reference(int (S::*)() const volatile&), int (S::*&)() const volatile&))]; }
+  { int a[T(__is_same(__add_lvalue_reference(int (S::*)() const volatile&&), int (S::*&)() const volatile&&))]; }
+}
+
+void add_rvalue_reference() {
+  { int a[T(__is_same(__add_rvalue_reference(void), void))]; }
+  { int a[T(__is_same(__add_rvalue_reference(const void), const void))]; }
+  { int a[T(__is_same(__add_rvalue_reference(volatile void), volatile void))]; }
+  { int a[T(__is_same(__add_rvalue_reference(const volatile void), const volatile void))]; }
+  { int a[T(__is_same(__add_rvalue_reference(int), int&&))]; }
+  { int a[T(__is_same(__add_rvalue_reference(const int), const int&&))]; }
+  { int a[T(__is_same(__add_rvalue_reference(volatile int), volatile int&&))]; }
+  { int a[T(__is_same(__add_rvalue_reference(const volatile int), const volatile int&&))]; }
+  { int a[T(__is_same(__add_rvalue_reference(int*), int*&&))]; }
+  { int a[T(__is_same(__add_rvalue_reference(int&), int&))]; } // reference collapsing
+  { int a[T(__is_same(__add_rvalue_reference(int&&), int&&))]; }
+  { int a[T(__is_same(__add_rvalue_reference(int()), int(&&)()))]; }
+  { int a[T(__is_same(__add_rvalue_reference(int(*)()), int(*&&)()))]; }
+  { int a[T(__is_same(__add_rvalue_reference(int(&)()), int(&)()))]; } // reference collapsing
+
+  { int a[T(__is_same(__add_rvalue_reference(S), S&&))]; }
+  { int a[T(__is_same(__add_rvalue_reference(const S), const S&&))]; }
+  { int a[T(__is_same(__add_rvalue_reference(volatile S), volatile S&&))]; }
+  { int a[T(__is_same(__add_rvalue_reference(const volatile S), const volatile S&&))]; }
+  { int a[T(__is_same(__add_rvalue_reference(int S::*), int S::*&&))]; }
+  { int a[T(__is_same(__add_rvalue_reference(int (S::*)()), int (S::*&&)()))]; }
+  { int a[T(__is_same(__add_rvalue_reference(int (S::*)() &), int (S::*&&)() &))]; }
+  { int a[T(__is_same(__add_rvalue_reference(int (S::*)() &&), int (S::*&&)() &&))]; }
+  { int a[T(__is_same(__add_rvalue_reference(int (S::*)() const), int (S::*&&)() const))]; }
+  { int a[T(__is_same(__add_rvalue_reference(int (S::*)() const&), int (S::*&&)() const&))]; }
+  { int a[T(__is_same(__add_rvalue_reference(int (S::*)() const&&), int (S::*&&)() const&&))]; }
+  { int a[T(__is_same(__add_rvalue_reference(int (S::*)() volatile), int (S::*&&)() volatile))]; }
+  { int a[T(__is_same(__add_rvalue_reference(int (S::*)() volatile&), int (S::*&&)() volatile&))]; }
+  { int a[T(__is_same(__add_rvalue_reference(int (S::*)() volatile&&), int (S::*&&)() volatile&&))]; }
+  { int a[T(__is_same(__add_rvalue_reference(int (S::*)() const volatile), int (S::*&&)() const volatile))]; }
+  { int a[T(__is_same(__add_rvalue_reference(int (S::*)() const volatile&), int (S::*&&)() const volatile&))]; }
+  { int a[T(__is_same(__add_rvalue_reference(int (S::*)() const volatile&&), int (S::*&&)() const volatile&&))]; }
+}
+
+void check_remove_reference() {
+  { int a[T(__is_same(__remove_reference(void), void))]; }
+  { int a[T(__is_same(__remove_reference(const volatile void), const volatile void))]; }
+  { int a[T(__is_same(__remove_reference(int), int))]; }
+  { int a[T(__is_same(__remove_reference(const int), const int))]; }
+  { int a[T(__is_same(__remove_reference(volatile int), volatile int))]; }
+  { int a[T(__is_same(__remove_reference(const volatile int), const volatile int))]; }
+  { int a[T(__is_same(__remove_reference(int*), int*))]; }
+  { int a[T(__is_same(__remove_reference(int* const volatile), int* const volatile))]; }
+  { int a[T(__is_same(__remove_reference(int const* const volatile), int const* const volatile))]; }
+  { int a[T(__is_same(__remove_reference(int&), int))]; }
+  { int a[T(__is_same(__remove_reference(int const volatile&), int const volatile))]; }
+  { int a[T(__is_same(__remove_reference(int&&), int))]; }
+  { int a[T(__is_same(__remove_reference(int const volatile&&), int const volatile))]; }
+  { int a[T(__is_same(__remove_reference(int()), int()))]; }
+  { int a[T(__is_same(__remove_reference(int(* const volatile)()), int(* const volatile)()))]; }
+  { int a[T(__is_same(__remove_reference(int(&)()), int()))]; }
+
+  { int a[T(__is_same(__remove_reference(S), S))]; }
+  { int a[T(__is_same(__remove_reference(S&), S))]; }
+  { int a[T(__is_same(__remove_reference(S&&), S))]; }
+  { int a[T(__is_same(__remove_reference(const S), const S))]; }
+  { int a[T(__is_same(__remove_reference(const S&), const S))]; }
+  { int a[T(__is_same(__remove_reference(const S&&), const S))]; }
+  { int a[T(__is_same(__remove_reference(volatile S), volatile S))]; }
+  { int a[T(__is_same(__remove_reference(volatile S&), volatile S))]; }
+  { int a[T(__is_same(__remove_reference(volatile S&&), volatile S))]; }
+  { int a[T(__is_same(__remove_reference(const volatile S), const volatile S))]; }
+  { int a[T(__is_same(__remove_reference(const volatile S&), const volatile S))]; }
+  { int a[T(__is_same(__remove_reference(const volatile S&&), const volatile S))]; }
+  { int a[T(__is_same(__remove_reference(int S::* const volatile&), int S::* const volatile))]; }
+  { int a[T(__is_same(__remove_reference(int (S::* const volatile&)()), int (S::* const volatile)()))]; }
+  { int a[T(__is_same(__remove_reference(int (S::* const volatile&)() &), int (S::* const volatile)() &))]; }
+  { int a[T(__is_same(__remove_reference(int (S::* const volatile&)() &&), int (S::* const volatile)() &&))]; }
+  { int a[T(__is_same(__remove_reference(int (S::* const volatile&)() const), int (S::* const volatile)() const))]; }
+  { int a[T(__is_same(__remove_reference(int (S::* const volatile&)() const&), int (S::* const volatile)() const&))]; }
+  { int a[T(__is_same(__remove_reference(int (S::* const volatile&)() const&&), int (S::* const volatile)() const&&))]; }
+  { int a[T(__is_same(__remove_reference(int (S::* const volatile&)() volatile), int (S::* const volatile)() volatile))]; }
+  { int a[T(__is_same(__remove_reference(int (S::* const volatile&)() volatile&), int (S::* const volatile)() volatile&))]; }
+  { int a[T(__is_same(__remove_reference(int (S::* const volatile&)() volatile&&), int (S::* const volatile)() volatile&&))]; }
+  { int a[T(__is_same(__remove_reference(int (S::* const volatile&)() const volatile), int (S::* const volatile)() const volatile))]; }
+  { int a[T(__is_same(__remove_reference(int (S::* const volatile&)() const volatile&), int (S::* const volatile)() const volatile&))]; }
+  { int a[T(__is_same(__remove_reference(int (S::* const volatile&)() const volatile&&), int (S::* const volatile)() const volatile&&))]; }
+  { int a[T(__is_same(__remove_reference(int (S::* const volatile&)()), int (S::* const volatile)()))]; }
+  { int a[T(__is_same(__remove_reference(int (S::* const volatile&&)() &), int (S::* const volatile)() &))]; }
+  { int a[T(__is_same(__remove_reference(int (S::* const volatile&&)() &&), int (S::* const volatile)() &&))]; }
+  { int a[T(__is_same(__remove_reference(int (S::* const volatile&&)() const), int (S::* const volatile)() const))]; }
+  { int a[T(__is_same(__remove_reference(int (S::* const volatile&&)() const&), int (S::* const volatile)() const&))]; }
+  { int a[T(__is_same(__remove_reference(int (S::* const volatile&&)() const&&), int (S::* const volatile)() const&&))]; }
+  { int a[T(__is_same(__remove_reference(int (S::* const volatile&&)() volatile), int (S::* const volatile)() volatile))]; }
+  { int a[T(__is_same(__remove_reference(int (S::* const volatile&&)() volatile&), int (S::* const volatile)() volatile&))]; }
+  { int a[T(__is_same(__remove_reference(int (S::* const volatile&&)() volatile&&), int (S::* const volatile)() volatile&&))]; }
+  { int a[T(__is_same(__remove_reference(int (S::* const volatile&&)() const volatile), int (S::* const volatile)() const volatile))]; }
+  { int a[T(__is_same(__remove_reference(int (S::* const volatile&&)() const volatile&), int (S::* const volatile)() const volatile&))]; }
+  { int a[T(__is_same(__remove_reference(int (S::* const volatile&&)() const volatile&&), int (S::* const volatile)() const volatile&&))]; }
+}
+
+void check_remove_cvref() {
+  { int a[T(__is_same(__remove_cvref(void), void))]; }
+  { int a[T(__is_same(__remove_cvref(const volatile void), void))]; }
+  { int a[T(__is_same(__remove_cvref(int), int))]; }
+  { int a[T(__is_same(__remove_cvref(const int), int))]; }
+  { int a[T(__is_same(__remove_cvref(volatile int), int))]; }
+  { int a[T(__is_same(__remove_cvref(const volatile int), int))]; }
+  { int a[T(__is_same(__remove_cvref(int*), int*))]; }
+  { int a[T(__is_same(__remove_cvref(int* const volatile), int*))]; }
+  { int a[T(__is_same(__remove_cvref(int const* const volatile), int const*))]; }
+  { int a[T(__is_same(__remove_cvref(int&), int))]; }
+  { int a[T(__is_same(__remove_cvref(int const volatile&), int))]; }
+  { int a[T(__is_same(__remove_cvref(int&&), int))]; }
+  { int a[T(__is_same(__remove_cvref(int const volatile&&), int))]; }
+  { int a[T(__is_same(__remove_cvref(int()), int()))]; }
+  { int a[T(__is_same(__remove_cvref(int(* const volatile)()), int(*)()))]; }
+  { int a[T(__is_same(__remove_cvref(int(&)()), int()))]; }
+
+  { int a[T(__is_same(__remove_cvref(S), S))]; }
+  { int a[T(__is_same(__remove_cvref(S&), S))]; }
+  { int a[T(__is_same(__remove_cvref(S&&), S))]; }
+  { int a[T(__is_same(__remove_cvref(const S), S))]; }
+  { int a[T(__is_same(__remove_cvref(const S&), S))]; }
+  { int a[T(__is_same(__remove_cvref(const S&&), S))]; }
+  { int a[T(__is_same(__remove_cvref(volatile S), S))]; }
+  { int a[T(__is_same(__remove_cvref(volatile S&), S))]; }
+  { int a[T(__is_same(__remove_cvref(volatile S&&), S))]; }
+  { int a[T(__is_same(__remove_cvref(const volatile S), S))]; }
+  { int a[T(__is_same(__remove_cvref(const volatile S&), S))]; }
+  { int a[T(__is_same(__remove_cvref(const volatile S&&), S))]; }
+  { int a[T(__is_same(__remove_cvref(int S::* const volatile), int S::*))]; }
+  { int a[T(__is_same(__remove_cvref(int (S::* const volatile)()), int (S::*)()))]; }
+  { int a[T(__is_same(__remove_cvref(int (S::* const volatile)() &), int (S::*)() &))]; }
+  { int a[T(__is_same(__remove_cvref(int (S::* const volatile)() &&), int (S::*)() &&))]; }
+  { int a[T(__is_same(__remove_cvref(int (S::* const volatile)() const), int (S::*)() const))]; }
+  { int a[T(__is_same(__remove_cvref(int (S::* const volatile)() const&), int (S::*)() const&))]; }
+  { int a[T(__is_same(__remove_cvref(int (S::* const volatile)() const&&), int (S::*)() const&&))]; }
+  { int a[T(__is_same(__remove_cvref(int (S::* const volatile)() volatile), int (S::*)() volatile))]; }
+  { int a[T(__is_same(__remove_cvref(int (S::* const volatile)() volatile&), int (S::*)() volatile&))]; }
+  { int a[T(__is_same(__remove_cvref(int (S::* const volatile)() volatile&&), int (S::*)() volatile&&))]; }
+  { int a[T(__is_same(__remove_cvref(int (S::* const volatile)() const volatile), int (S::*)() const volatile))]; }
+  { int a[T(__is_same(__remove_cvref(int (S::* const volatile)() const volatile&), int (S::*)() const volatile&))]; }
+  { int a[T(__is_same(__remove_cvref(int (S::* const volatile)() const volatile&&), int (S::*)() const volatile&&))]; }
+  { int a[T(__is_same(__remove_cvref(int S::* const volatile&), int S::*))]; }
+  { int a[T(__is_same(__remove_cvref(int (S::* const volatile&)()), int (S::*)()))]; }
+  { int a[T(__is_same(__remove_cvref(int (S::* const volatile&)() &), int (S::*)() &))]; }
+  { int a[T(__is_same(__remove_cvref(int (S::* const volatile&)() &&), int (S::*)() &&))]; }
+  { int a[T(__is_same(__remove_cvref(int (S::* const volatile&)() const), int (S::*)() const))]; }
+  { int a[T(__is_same(__remove_cvref(int (S::* const volatile&)() const&), int (S::*)() const&))]; }
+  { int a[T(__is_same(__remove_cvref(int (S::* const volatile&)() const&&), int (S::*)() const&&))]; }
+  { int a[T(__is_same(__remove_cvref(int (S::* const volatile&)() volatile), int (S::*)() volatile))]; }
+  { int a[T(__is_same(__remove_cvref(int (S::* const volatile&)() volatile&), int (S::*)() volatile&))]; }
+  { int a[T(__is_same(__remove_cvref(int (S::* const volatile&)() volatile&&), int (S::*)() volatile&&))]; }
+  { int a[T(__is_same(__remove_cvref(int (S::* const volatile&)() const volatile), int (S::*)() const volatile))]; }
+  { int a[T(__is_same(__remove_cvref(int (S::* const volatile&)() const volatile&), int (S::*)() const volatile&))]; }
+  { int a[T(__is_same(__remove_cvref(int (S::* const volatile&)() const volatile&&), int (S::*)() const volatile&&))]; }
+  { int a[T(__is_same(__remove_cvref(int S::* const volatile&&), int S::*))]; }
+  { int a[T(__is_same(__remove_cvref(int (S::* const volatile&&)()), int (S::*)()))]; }
+  { int a[T(__is_same(__remove_cvref(int (S::* const volatile&&)() &), int (S::*)() &))]; }
+  { int a[T(__is_same(__remove_cvref(int (S::* const volatile&&)() &&), int (S::*)() &&))]; }
+  { int a[T(__is_same(__remove_cvref(int (S::* const volatile&&)() const), int (S::*)() const))]; }
+  { int a[T(__is_same(__remove_cvref(int (S::* const volatile&&)() const&), int (S::*)() const&))]; }
+  { int a[T(__is_same(__remove_cvref(int (S::* const volatile&&)() const&&), int (S::*)() const&&))]; }
+  { int a[T(__is_same(__remove_cvref(int (S::* const volatile&&)() volatile), int (S::*)() volatile))]; }
+  { int a[T(__is_same(__remove_cvref(int (S::* const volatile&&)() volatile&), int (S::*)() volatile&))]; }
+  { int a[T(__is_same(__remove_cvref(int (S::* const volatile&&)() volatile&&), int (S::*)() volatile&&))]; }
+  { int a[T(__is_same(__remove_cvref(int (S::* const volatile&&)() const volatile), int (S::*)() const volatile))]; }
+  { int a[T(__is_same(__remove_cvref(int (S::* const volatile&&)() const volatile&), int (S::*)() const volatile&))]; }
+  { int a[T(__is_same(__remove_cvref(int (S::* const volatile&&)() const volatile&&), int (S::*)() const volatile&&))]; }
+}
+
+void check_decay() {
+  { int a[T(__is_same(__decay(void), void))]; }
+  { int a[T(__is_same(__decay(const volatile void), void))]; }
+  { int a[T(__is_same(__decay(int), int))]; }
+  { int a[T(__is_same(__decay(const int), int))]; }
+  { int a[T(__is_same(__decay(volatile int), int))]; }
+  { int a[T(__is_same(__decay(const volatile int), int))]; }
+  { int a[T(__is_same(__decay(int*), int*))]; }
+  { int a[T(__is_same(__decay(int* const volatile), int*))]; }
+  { int a[T(__is_same(__decay(int const* const volatile), int const*))]; }
+  { int a[T(__is_same(__decay(int&), int))]; }
+  { int a[T(__is_same(__decay(int const volatile&), int))]; }
+  { int a[T(__is_same(__decay(int&&), int))]; }
+  { int a[T(__is_same(__decay(int const volatile&&), int))]; }
+  { int a[T(__is_same(__decay(int()), int(*)()))]; }
+  { int a[T(__is_same(__decay(int(*)()), int(*)()))]; }
+  { int a[T(__is_same(__decay(int(* const)()), int(*)()))]; }
+  { int a[T(__is_same(__decay(int(* volatile)()), int(*)()))]; }
+  { int a[T(__is_same(__decay(int(* const volatile)()), int(*)()))]; }
+  { int a[T(__is_same(__decay(int(&)()), int(*)()))]; }
+  { int a[T(__is_same(__decay(IntAr), int*))]; }
+  { int a[T(__is_same(__decay(IntArNB), int*))]; }
+
+  { int a[T(__is_same(__decay(S), S))]; }
+  { int a[T(__is_same(__decay(S&), S))]; }
+  { int a[T(__is_same(__decay(S&&), S))]; }
+  { int a[T(__is_same(__decay(const S), S))]; }
+  { int a[T(__is_same(__decay(const S&), S))]; }
+  { int a[T(__is_same(__decay(const S&&), S))]; }
+  { int a[T(__is_same(__decay(volatile S), S))]; }
+  { int a[T(__is_same(__decay(volatile S&), S))]; }
+  { int a[T(__is_same(__decay(volatile S&&), S))]; }
+  { int a[T(__is_same(__decay(const volatile S), S))]; }
+  { int a[T(__is_same(__decay(const volatile S&), S))]; }
+  { int a[T(__is_same(__decay(const volatile S&&), S))]; }
+  { int a[T(__is_same(__decay(int S::* const volatile), int S::*))]; }
+  { int a[T(__is_same(__decay(int (S::* const volatile)()), int (S::*)()))]; }
+  { int a[T(__is_same(__decay(int (S::* const volatile)() &), int (S::*)() &))]; }
+  { int a[T(__is_same(__decay(int (S::* const volatile)() &&), int (S::*)() &&))]; }
+  { int a[T(__is_same(__decay(int (S::* const volatile)() const), int (S::*)() const))]; }
+  { int a[T(__is_same(__decay(int (S::* const volatile)() const&), int (S::*)() const&))]; }
+  { int a[T(__is_same(__decay(int (S::* const volatile)() const&&), int (S::*)() const&&))]; }
+  { int a[T(__is_same(__decay(int (S::* const volatile)() volatile), int (S::*)() volatile))]; }
+  { int a[T(__is_same(__decay(int (S::* const volatile)() volatile&), int (S::*)() volatile&))]; }
+  { int a[T(__is_same(__decay(int (S::* const volatile)() volatile&&), int (S::*)() volatile&&))]; }
+  { int a[T(__is_same(__decay(int (S::* const volatile)() const volatile), int (S::*)() const volatile))]; }
+  { int a[T(__is_same(__decay(int (S::* const volatile)() const volatile&), int (S::*)() const volatile&))]; }
+  { int a[T(__is_same(__decay(int (S::* const volatile)() const volatile&&), int (S::*)() const volatile&&))]; }
+  { int a[T(__is_same(__decay(int S::* const volatile&), int S::*))]; }
+  { int a[T(__is_same(__decay(int (S::* const volatile&)()), int (S::*)()))]; }
+  { int a[T(__is_same(__decay(int (S::* const volatile&)() &), int (S::*)() &))]; }
+  { int a[T(__is_same(__decay(int (S::* const volatile&)() &&), int (S::*)() &&))]; }
+  { int a[T(__is_same(__decay(int (S::* const volatile&)() const), int (S::*)() const))]; }
+  { int a[T(__is_same(__decay(int (S::* const volatile&)() const&), int (S::*)() const&))]; }
+  { int a[T(__is_same(__decay(int (S::* const volatile&)() const&&), int (S::*)() const&&))]; }
+  { int a[T(__is_same(__decay(int (S::* const volatile&)() volatile), int (S::*)() volatile))]; }
+  { int a[T(__is_same(__decay(int (S::* const volatile&)() volatile&), int (S::*)() volatile&))]; }
+  { int a[T(__is_same(__decay(int (S::* const volatile&)() volatile&&), int (S::*)() volatile&&))]; }
+  { int a[T(__is_same(__decay(int (S::* const volatile&)() const volatile), int (S::*)() const volatile))]; }
+  { int a[T(__is_same(__decay(int (S::* const volatile&)() const volatile&), int (S::*)() const volatile&))]; }
+  { int a[T(__is_same(__decay(int (S::* const volatile&)() const volatile&&), int (S::*)() const volatile&&))]; }
+  { int a[T(__is_same(__decay(int S::* const volatile&&), int S::*))]; }
+  { int a[T(__is_same(__decay(int (S::* const volatile&&)()), int (S::*)()))]; }
+  { int a[T(__is_same(__decay(int (S::* const volatile&&)() &), int (S::*)() &))]; }
+  { int a[T(__is_same(__decay(int (S::* const volatile&&)() &&), int (S::*)() &&))]; }
+  { int a[T(__is_same(__decay(int (S::* const volatile&&)() const), int (S::*)() const))]; }
+  { int a[T(__is_same(__decay(int (S::* const volatile&&)() const&), int (S::*)() const&))]; }
+  { int a[T(__is_same(__decay(int (S::* const volatile&&)() const&&), int (S::*)() const&&))]; }
+  { int a[T(__is_same(__decay(int (S::* const volatile&&)() volatile), int (S::*)() volatile))]; }
+  { int a[T(__is_same(__decay(int (S::* const volatile&&)() volatile&), int (S::*)() volatile&))]; }
+  { int a[T(__is_same(__decay(int (S::* const volatile&&)() volatile&&), int (S::*)() volatile&&))]; }
+  { int a[T(__is_same(__decay(int (S::* const volatile&&)() const volatile), int (S::*)() const volatile))]; }
+  { int a[T(__is_same(__decay(int (S::* const volatile&&)() const volatile&), int (S::*)() const volatile&))]; }
+  { int a[T(__is_same(__decay(int (S::* const volatile&&)() const volatile&&), int (S::*)() const volatile&&))]; }
+}
+
+template<class T> struct CheckAbominableFunction {};
+template<class M>
+struct CheckAbominableFunction<M S::*> {
+  static void checks()
+  {
+    { int a[T(__is_same(__add_const(M), const M))]; }
+    { int a[T(__is_same(__add_volatile(M), volatile M))]; }
+    { int a[T(__is_same(__add_cv(M), const volatile M))]; }
+    { int a[T(__is_same(__add_lvalue_reference(M), M))]; }
+    { int a[T(__is_same(__add_pointer(M), M))]; }
+    { int a[T(__is_same(__add_rvalue_reference(M), M))]; }
+    { int a[T(__is_same(__remove_const(M), M))]; }
+    { int a[T(__is_same(__remove_volatile(M), M))]; }
+    { int a[T(__is_same(__remove_cv(M), M))]; }
+    { int a[T(__is_same(__remove_cvref(M), M))]; }
+    { int a[T(__is_same(__remove_pointer(M), M))]; }
+    { int a[T(__is_same(__remove_reference(M), M))]; }
+  }
+};
+
+template struct CheckAbominableFunction<int (S::*)() &>;
+template struct CheckAbominableFunction<int (S::*)() &&>;
+template struct CheckAbominableFunction<int (S::*)() const>;
+template struct CheckAbominableFunction<int (S::*)() const&>;
+template struct CheckAbominableFunction<int (S::*)() const&&>;
+template struct CheckAbominableFunction<int (S::*)() volatile>;
+template struct CheckAbominableFunction<int (S::*)() volatile&>;
+template struct CheckAbominableFunction<int (S::*)() volatile&&>;
+template struct CheckAbominableFunction<int (S::*)() const volatile>;
+template struct CheckAbominableFunction<int (S::*)() const volatile&>;
+template struct CheckAbominableFunction<int (S::*)() const volatile&&>;
Index: clang/lib/Sema/SemaType.cpp
===================================================================
--- clang/lib/Sema/SemaType.cpp
+++ clang/lib/Sema/SemaType.cpp
@@ -19,9 +19,11 @@
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
 #include "clang/AST/TypeLoc.h"
 #include "clang/AST/TypeLocVisitor.h"
 #include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/Specifiers.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Sema/DeclSpec.h"
@@ -1257,6 +1259,42 @@
   return OpenCLAccessAttr::Keyword_read_only;
 }
 
+static UnaryTransformType::UTTKind
+TSTToUnaryTransformType(DeclSpec::TST SwitchTST) {
+  switch (SwitchTST) {
+  case TST_add_const:
+    return UnaryTransformType::AddConst;
+  case TST_add_cv:
+    return UnaryTransformType::AddCV;
+  case TST_add_lvalue_reference:
+    return UnaryTransformType::AddLvalueReference;
+  case TST_add_pointer:
+    return UnaryTransformType::AddPointer;
+  case TST_add_rvalue_reference:
+    return UnaryTransformType::AddRvalueReference;
+  case TST_add_volatile:
+    return UnaryTransformType::AddVolatile;
+  case TST_decay:
+    return UnaryTransformType::Decay;
+  case TST_remove_const:
+    return UnaryTransformType::RemoveConst;
+  case TST_remove_cv:
+    return UnaryTransformType::RemoveCV;
+  case TST_remove_cvref:
+    return UnaryTransformType::RemoveCVRef;
+  case TST_remove_pointer:
+    return UnaryTransformType::RemovePointer;
+  case TST_remove_reference:
+    return UnaryTransformType::RemoveReference;
+  case TST_remove_volatile:
+    return UnaryTransformType::RemoveVolatile;
+  case TST_underlyingType:
+    return UnaryTransformType::EnumUnderlyingType;
+  default:
+    llvm_unreachable("attempted to parse a non-unary transform builtin");
+  }
+}
+
 /// Convert the specified declspec to the appropriate type
 /// object.
 /// \param state Specifies the declarator containing the declaration specifier
@@ -1640,13 +1678,27 @@
     break;
   }
   case DeclSpec::TST_underlyingType:
+  case DeclSpec::TST_add_const:
+  case DeclSpec::TST_add_cv:
+  case DeclSpec::TST_add_lvalue_reference:
+  case DeclSpec::TST_add_pointer:
+  case DeclSpec::TST_add_rvalue_reference:
+  case DeclSpec::TST_add_volatile:
+  case DeclSpec::TST_decay:
+  case DeclSpec::TST_remove_const:
+  case DeclSpec::TST_remove_cv:
+  case DeclSpec::TST_remove_cvref:
+  case DeclSpec::TST_remove_pointer:
+  case DeclSpec::TST_remove_reference:
+  case DeclSpec::TST_remove_volatile:
     Result = S.GetTypeFromParser(DS.getRepAsType());
-    assert(!Result.isNull() && "Didn't get a type for __underlying_type?");
-    Result = S.BuildUnaryTransformType(Result,
-                                       UnaryTransformType::EnumUnderlyingType,
-                                       DS.getTypeSpecTypeLoc());
+    assert(!Result.isNull() && "Didn't get a type for the transformation?");
+    Result = S.BuildUnaryTransformType(
+        Result, TSTToUnaryTransformType(DS.getTypeSpecType()),
+        DS.getTypeSpecTypeLoc());
     if (Result.isNull()) {
-      Result = Context.IntTy;
+      if (DS.getTypeSpecType() == DeclSpec::TST_underlyingType)
+        Result = Context.IntTy;
       declarator.setInvalidType(true);
     }
     break;
@@ -5974,8 +6026,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_remove_volatile);
       TL.setKWLoc(DS.getTypeSpecTypeLoc());
       TL.setParensRange(DS.getTypeofParensRange());
       assert(DS.getRepAsType());
@@ -9065,6 +9118,87 @@
       return Context.getUnaryTransformType(BaseType, Underlying,
                                         UnaryTransformType::EnumUnderlyingType);
     }
+  case UnaryTransformType::AddPointer: {
+    DeclarationName EntityName(BaseType.getBaseTypeIdentifier());
+    QualType PointerToT =
+        QualType(BaseType).isReferenceable() || BaseType->isVoidType()
+            ? BuildPointerType(BaseType.getNonReferenceType(), Loc, EntityName)
+            : BaseType;
+    return Context.getUnaryTransformType(BaseType, PointerToT, UKind);
+  }
+  case UnaryTransformType::RemovePointer: {
+    if (!BaseType->isPointerType())
+      return BaseType;
+    return BaseType->getPointeeType();
+  }
+  case UnaryTransformType::Decay: {
+    QualType Underlying = BaseType.getNonReferenceType();
+    if (Underlying->isArrayType() || Underlying->isFunctionType())
+      return Context.getUnaryTransformType(
+          BaseType, Context.getDecayedType(Underlying), UKind);
+
+    Qualifiers Quals = Underlying.getQualifiers();
+    Quals.removeCVRQualifiers();
+    return Context.getUnaryTransformType(
+        BaseType,
+        QualType(Underlying.getSplitUnqualifiedType().Ty,
+                 Quals.getAsOpaqueValue()),
+        UKind);
+    ;
+  }
+  case UnaryTransformType::AddLvalueReference:
+  case UnaryTransformType::AddRvalueReference: {
+    DeclarationName EntityName(BaseType.getBaseTypeIdentifier());
+    QualType PointerToT =
+        QualType(BaseType).isReferenceable()
+            ? BuildReferenceType(
+                  BaseType, UKind == UnaryTransformType::AddLvalueReference,
+                  Loc, EntityName)
+            : BaseType;
+    return Context.getUnaryTransformType(BaseType, PointerToT, UKind);
+  }
+  case UnaryTransformType::RemoveCVRef:
+  case UnaryTransformType::RemoveReference: {
+    QualType Underlying = BaseType.getNonReferenceType();
+    Qualifiers Quals = Underlying.getQualifiers();
+    if (UKind == UnaryTransformType::RemoveCVRef) {
+      Quals.removeConst();
+      Quals.removeVolatile();
+    }
+    return Context.getUnaryTransformType(
+        BaseType,
+        QualType(Underlying.getSplitUnqualifiedType().Ty,
+                 Quals.getAsOpaqueValue()),
+        UKind);
+  }
+  case UnaryTransformType::AddConst:
+  case UnaryTransformType::AddCV:
+  case UnaryTransformType::AddVolatile:
+  case UnaryTransformType::RemoveConst:
+  case UnaryTransformType::RemoveCV:
+  case UnaryTransformType::RemoveVolatile: {
+    SplitQualType Split = BaseType.getSplitUnqualifiedType();
+    Qualifiers Quals = BaseType.getQualifiers();
+    if (BaseType->isReferenceType() || BaseType->isFunctionType())
+      return BaseType;
+
+    if (UKind == UnaryTransformType::AddConst ||
+        UKind == UnaryTransformType::AddCV)
+      Quals.addConst();
+    if (UKind == UnaryTransformType::AddVolatile ||
+        UKind == UnaryTransformType::AddCV)
+      Quals.addVolatile();
+
+    if (UKind == UnaryTransformType::RemoveConst ||
+        UKind == UnaryTransformType::RemoveCV)
+      Quals.removeConst();
+    if (UKind == UnaryTransformType::RemoveVolatile ||
+        UKind == UnaryTransformType::RemoveCV)
+      Quals.removeVolatile();
+
+    QualType Underlying(Split.Ty, Quals.getAsOpaqueValue());
+    return Context.getUnaryTransformType(BaseType, Underlying, UKind);
+  }
   }
   llvm_unreachable("unknown unary transform type");
 }
Index: clang/lib/Sema/SemaTemplateVariadic.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateVariadic.cpp
+++ clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -861,6 +861,19 @@
   case TST_typename:
   case TST_typeofType:
   case TST_underlyingType:
+  case TST_add_const:
+  case TST_add_cv:
+  case TST_add_lvalue_reference:
+  case TST_add_pointer:
+  case TST_add_rvalue_reference:
+  case TST_add_volatile:
+  case TST_decay:
+  case TST_remove_const:
+  case TST_remove_cv:
+  case TST_remove_cvref:
+  case TST_remove_pointer:
+  case TST_remove_reference:
+  case TST_remove_volatile:
   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
@@ -145,6 +145,15 @@
   case tok::kw_wchar_t:
   case tok::kw_bool:
   case tok::kw___underlying_type:
+  case tok::kw___add_const:
+  case tok::kw___add_cv:
+  case tok::kw___add_volatile:
+  case tok::kw___decay:
+  case tok::kw___remove_const:
+  case tok::kw___remove_cv:
+  case tok::kw___remove_cvref:
+  case tok::kw___remove_reference:
+  case tok::kw___remove_volatile:
   case tok::kw___auto_type:
     return true;
 
@@ -5599,6 +5608,15 @@
   case DeclSpec::TST_typename:
   case DeclSpec::TST_typeofType:
   case DeclSpec::TST_underlyingType:
+  case DeclSpec::TST_add_const:
+  case DeclSpec::TST_add_cv:
+  case DeclSpec::TST_add_volatile:
+  case DeclSpec::TST_decay:
+  case DeclSpec::TST_remove_const:
+  case DeclSpec::TST_remove_cv:
+  case DeclSpec::TST_remove_cvref:
+  case DeclSpec::TST_remove_reference:
+  case DeclSpec::TST_remove_volatile:
   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
@@ -18,6 +18,7 @@
 #include "clang/AST/TypeLoc.h"
 #include "clang/Basic/LangOptions.h"
 #include "clang/Basic/SourceManager.h"
+#include "clang/Basic/Specifiers.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Sema/ParsedTemplate.h"
 #include "clang/Sema/Sema.h"
@@ -390,6 +391,19 @@
       return false;
 
     case TST_underlyingType:
+    case TST_add_const:
+    case TST_add_cv:
+    case TST_add_lvalue_reference:
+    case TST_add_pointer:
+    case TST_add_rvalue_reference:
+    case TST_add_volatile:
+    case TST_decay:
+    case TST_remove_const:
+    case TST_remove_cv:
+    case TST_remove_cvref:
+    case TST_remove_pointer:
+    case TST_remove_reference:
+    case TST_remove_volatile:
     case TST_typename:
     case TST_typeofType: {
       QualType QT = DS.getRepAsType().get();
@@ -577,6 +591,32 @@
   case DeclSpec::TST_decltype:    return "(decltype)";
   case DeclSpec::TST_decltype_auto: return "decltype(auto)";
   case DeclSpec::TST_underlyingType: return "__underlying_type";
+  case DeclSpec::TST_add_const:
+    return "__add_const";
+  case DeclSpec::TST_add_cv:
+    return "__add_cv";
+  case DeclSpec::TST_add_lvalue_reference:
+    return "__add_lvalue_reference";
+  case DeclSpec::TST_add_pointer:
+    return "__add_pointer";
+  case DeclSpec::TST_add_rvalue_reference:
+    return "__add_rvalue_reference";
+  case DeclSpec::TST_add_volatile:
+    return "__add_volatile";
+  case DeclSpec::TST_decay:
+    return "__decay";
+  case DeclSpec::TST_remove_const:
+    return "__remove_const";
+  case DeclSpec::TST_remove_cv:
+    return "__remove_cv";
+  case DeclSpec::TST_remove_cvref:
+    return "__remove_cvref";
+  case DeclSpec::TST_remove_pointer:
+    return "__remove_pointer";
+  case DeclSpec::TST_remove_reference:
+    return "__remove_reference";
+  case DeclSpec::TST_remove_volatile:
+    return "__remove_volatile";
   case DeclSpec::TST_unknown_anytype: return "__unknown_anytype";
   case DeclSpec::TST_atomic: return "_Atomic";
   case DeclSpec::TST_BFloat16: return "__bf16";
Index: clang/lib/Parse/ParseDeclCXX.cpp
===================================================================
--- clang/lib/Parse/ParseDeclCXX.cpp
+++ clang/lib/Parse/ParseDeclCXX.cpp
@@ -1508,61 +1508,73 @@
   // C++11 attributes
   SourceLocation AttrFixitLoc = Tok.getLocation();
 
-  if (TagType == DeclSpec::TST_struct &&
-      Tok.isNot(tok::identifier) &&
-      !Tok.isAnnotation() &&
-      Tok.getIdentifierInfo() &&
-      Tok.isOneOf(tok::kw___is_abstract,
-                  tok::kw___is_aggregate,
-                  tok::kw___is_arithmetic,
-                  tok::kw___is_array,
-                  tok::kw___is_assignable,
-                  tok::kw___is_base_of,
-                  tok::kw___is_class,
-                  tok::kw___is_complete_type,
-                  tok::kw___is_compound,
-                  tok::kw___is_const,
-                  tok::kw___is_constructible,
-                  tok::kw___is_convertible,
-                  tok::kw___is_convertible_to,
-                  tok::kw___is_destructible,
-                  tok::kw___is_empty,
-                  tok::kw___is_enum,
-                  tok::kw___is_floating_point,
-                  tok::kw___is_final,
-                  tok::kw___is_function,
-                  tok::kw___is_fundamental,
-                  tok::kw___is_integral,
-                  tok::kw___is_interface_class,
-                  tok::kw___is_literal,
-                  tok::kw___is_lvalue_expr,
-                  tok::kw___is_lvalue_reference,
-                  tok::kw___is_member_function_pointer,
-                  tok::kw___is_member_object_pointer,
-                  tok::kw___is_member_pointer,
-                  tok::kw___is_nothrow_assignable,
-                  tok::kw___is_nothrow_constructible,
-                  tok::kw___is_nothrow_destructible,
-                  tok::kw___is_object,
-                  tok::kw___is_pod,
-                  tok::kw___is_pointer,
-                  tok::kw___is_polymorphic,
-                  tok::kw___is_reference,
-                  tok::kw___is_rvalue_expr,
-                  tok::kw___is_rvalue_reference,
-                  tok::kw___is_same,
-                  tok::kw___is_scalar,
-                  tok::kw___is_sealed,
-                  tok::kw___is_signed,
-                  tok::kw___is_standard_layout,
-                  tok::kw___is_trivial,
-                  tok::kw___is_trivially_assignable,
-                  tok::kw___is_trivially_constructible,
-                  tok::kw___is_trivially_copyable,
-                  tok::kw___is_union,
-                  tok::kw___is_unsigned,
-                  tok::kw___is_void,
-                  tok::kw___is_volatile))
+  if (TagType == DeclSpec::TST_struct && Tok.isNot(tok::identifier) &&
+      !Tok.isAnnotation() && Tok.getIdentifierInfo() &&
+      Tok.isOneOf( // clang-format off
+          tok::kw___add_const,
+          tok::kw___add_cv,
+          tok::kw___add_lvalue_reference,
+          tok::kw___add_pointer,
+          tok::kw___add_rvalue_reference,
+          tok::kw___add_volatile,
+          tok::kw___decay,
+          tok::kw___is_abstract,
+          tok::kw___is_aggregate,
+          tok::kw___is_arithmetic,
+          tok::kw___is_array,
+          tok::kw___is_assignable,
+          tok::kw___is_base_of,
+          tok::kw___is_class,
+          tok::kw___is_complete_type,
+          tok::kw___is_compound,
+          tok::kw___is_const,
+          tok::kw___is_constructible,
+          tok::kw___is_convertible,
+          tok::kw___is_convertible_to,
+          tok::kw___is_destructible,
+          tok::kw___is_empty,
+          tok::kw___is_enum,
+          tok::kw___is_floating_point,
+          tok::kw___is_final,
+          tok::kw___is_function,
+          tok::kw___is_fundamental,
+          tok::kw___is_integral,
+          tok::kw___is_interface_class,
+          tok::kw___is_literal,
+          tok::kw___is_lvalue_expr,
+          tok::kw___is_lvalue_reference,
+          tok::kw___is_member_function_pointer,
+          tok::kw___is_member_object_pointer,
+          tok::kw___is_member_pointer,
+          tok::kw___is_nothrow_assignable,
+          tok::kw___is_nothrow_constructible,
+          tok::kw___is_nothrow_destructible,
+          tok::kw___is_object,
+          tok::kw___is_pod,
+          tok::kw___is_pointer,
+          tok::kw___is_polymorphic,
+          tok::kw___is_reference,
+          tok::kw___is_rvalue_expr,
+          tok::kw___is_rvalue_reference,
+          tok::kw___is_same,
+          tok::kw___is_scalar,
+          tok::kw___is_sealed,
+          tok::kw___is_signed,
+          tok::kw___is_standard_layout,
+          tok::kw___is_trivial,
+          tok::kw___is_trivially_assignable,
+          tok::kw___is_trivially_constructible,
+          tok::kw___is_trivially_copyable,
+          tok::kw___is_union,
+          tok::kw___is_unsigned,
+          tok::kw___is_void,
+          tok::kw___is_volatile,
+          tok::kw___remove_const,
+          tok::kw___remove_cv,
+          tok::kw___remove_cvref,
+          tok::kw___remove_pointer,
+          tok::kw___remove_reference,
+          tok::kw___remove_volatile)) // clang-format on
     // GNU libstdc++ 4.2 and libc++ use certain intrinsic names as the
     // name of struct templates, but some are keywords in GCC >= 4.3
     // and Clang. Therefore, when we see the token sequence "struct
Index: clang/lib/Parse/ParseDecl.cpp
===================================================================
--- clang/lib/Parse/ParseDecl.cpp
+++ clang/lib/Parse/ParseDecl.cpp
@@ -4115,6 +4115,22 @@
       ParseUnderlyingTypeSpecifier(DS);
       continue;
 
+    case tok::kw___add_const:
+    case tok::kw___add_cv:
+    case tok::kw___add_lvalue_reference:
+    case tok::kw___add_pointer:
+    case tok::kw___add_rvalue_reference:
+    case tok::kw___add_volatile:
+    case tok::kw___decay:
+    case tok::kw___remove_const:
+    case tok::kw___remove_cv:
+    case tok::kw___remove_cvref:
+    case tok::kw___remove_pointer:
+    case tok::kw___remove_reference:
+    case tok::kw___remove_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,
@@ -4215,6 +4231,68 @@
   }
 }
 
+DeclSpec::TST Parser::TypeTransformTokToDeclSpec() {
+  switch (Tok.getKind()) {
+  case tok::kw___add_const:
+    return DeclSpec::TST_add_const;
+  case tok::kw___add_cv:
+    return DeclSpec::TST_add_cv;
+  case tok::kw___add_lvalue_reference:
+    return DeclSpec::TST_add_lvalue_reference;
+  case tok::kw___add_pointer:
+    return DeclSpec::TST_add_pointer;
+  case tok::kw___add_rvalue_reference:
+    return DeclSpec::TST_add_rvalue_reference;
+  case tok::kw___add_volatile:
+    return DeclSpec::TST_add_volatile;
+  case tok::kw___decay:
+    return DeclSpec::TST_decay;
+  case tok::kw___remove_const:
+    return DeclSpec::TST_remove_const;
+  case tok::kw___remove_cv:
+    return DeclSpec::TST_remove_cv;
+  case tok::kw___remove_cvref:
+    return DeclSpec::TST_remove_cvref;
+  case tok::kw___remove_pointer:
+    return DeclSpec::TST_remove_pointer;
+  case tok::kw___remove_reference:
+    return DeclSpec::TST_remove_reference;
+  case tok::kw___remove_volatile:
+    return DeclSpec::TST_remove_volatile;
+  default:
+    llvm_unreachable(__FILE__
+                     "passed in an unhandled type transformation built-in");
+  }
+}
+
+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,
+                         "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());
+}
+
 /// ParseStructDeclaration - Parse a struct declaration without the terminating
 /// semicolon.
 ///
Index: clang/lib/Lex/PPMacroExpansion.cpp
===================================================================
--- clang/lib/Lex/PPMacroExpansion.cpp
+++ clang/lib/Lex/PPMacroExpansion.cpp
@@ -1658,6 +1658,19 @@
               .Case("__array_extent", true)
               .Case("__reference_binds_to_temporary", true)
               .Case("__underlying_type", true)
+              .Case("__add_const", true)
+              .Case("__add_cv", true)
+              .Case("__add_lvalue_reference", true)
+              .Case("__add_pointer", true)
+              .Case("__add_rvalue_reference", true)
+              .Case("__add_volatile", true)
+              .Case("__decay", true)
+              .Case("__remove_const", true)
+              .Case("__remove_cv", true)
+              .Case("__remove_cvref", true)
+              .Case("__remove_pointer", true)
+              .Case("__remove_reference", true)
+              .Case("__remove_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
@@ -57,6 +57,19 @@
   case tok::kw_wchar_t:
   case tok::kw_bool:
   case tok::kw___underlying_type:
+  case tok::kw___add_const:
+  case tok::kw___add_cv:
+  case tok::kw___add_lvalue_reference:
+  case tok::kw___add_pointer:
+  case tok::kw___add_rvalue_reference:
+  case tok::kw___add_volatile:
+  case tok::kw___decay:
+  case tok::kw___remove_const:
+  case tok::kw___remove_cv:
+  case tok::kw___remove_cvref:
+  case tok::kw___remove_pointer:
+  case tok::kw___remove_reference:
+  case tok::kw___remove_volatile:
   case tok::annot_typename:
   case tok::kw_char8_t:
   case tok::kw_char16_t:
Index: clang/lib/AST/TypePrinter.cpp
===================================================================
--- clang/lib/AST/TypePrinter.cpp
+++ clang/lib/AST/TypePrinter.cpp
@@ -22,6 +22,7 @@
 #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"
@@ -32,6 +33,7 @@
 #include "clang/Basic/SourceManager.h"
 #include "clang/Basic/Specifiers.h"
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/Twine.h"
@@ -1119,11 +1121,40 @@
 
   switch (T->getUTTKind()) {
     case UnaryTransformType::EnumUnderlyingType:
-      OS << "__underlying_type(";
+    case UnaryTransformType::AddConst:
+    case UnaryTransformType::AddCV:
+    case UnaryTransformType::AddLvalueReference:
+    case UnaryTransformType::AddPointer:
+    case UnaryTransformType::AddRvalueReference:
+    case UnaryTransformType::AddVolatile:
+    case UnaryTransformType::Decay:
+    case UnaryTransformType::RemoveConst:
+    case UnaryTransformType::RemoveCV:
+    case UnaryTransformType::RemoveCVRef:
+    case UnaryTransformType::RemovePointer:
+    case UnaryTransformType::RemoveReference:
+    case UnaryTransformType::RemoveVolatile: {
+      static llvm::DenseMap<int, const char *> Transformation = {
+          {{UnaryTransformType::EnumUnderlyingType, "__underlying_type"},
+           {UnaryTransformType::AddConst, "__add_const"},
+           {UnaryTransformType::AddCV, "__add_cv"},
+           {UnaryTransformType::AddLvalueReference, "__add_lvalue_reference"},
+           {UnaryTransformType::AddPointer, "__add_pointer"},
+           {UnaryTransformType::AddRvalueReference, "__add_rvalue_reference"},
+           {UnaryTransformType::AddVolatile, "__add_volatile"},
+           {UnaryTransformType::Decay, "__decay"},
+           {UnaryTransformType::RemoveConst, "__remove_const"},
+           {UnaryTransformType::RemoveCV, "__remove_cv"},
+           {UnaryTransformType::RemoveCVRef, "__remove_cvref"},
+           {UnaryTransformType::RemovePointer, "__remove_pointer"},
+           {UnaryTransformType::RemoveReference, "__remove_reference"},
+           {UnaryTransformType::RemoveVolatile, "__remove_volatile"}}};
+      OS << Transformation[T->getUTTKind()] << '(';
       print(T->getBaseType(), OS, StringRef());
       OS << ')';
       spaceBeforePlaceHolder(OS);
       return;
+    }
   }
 
   printBefore(T->getBaseType(), OS);
@@ -1135,6 +1166,18 @@
 
   switch (T->getUTTKind()) {
     case UnaryTransformType::EnumUnderlyingType:
+    case UnaryTransformType::AddConst:
+    case UnaryTransformType::AddCV:
+    case UnaryTransformType::AddLvalueReference:
+    case UnaryTransformType::AddPointer:
+    case UnaryTransformType::AddRvalueReference:
+    case UnaryTransformType::AddVolatile:
+    case UnaryTransformType::RemoveConst:
+    case UnaryTransformType::RemoveCV:
+    case UnaryTransformType::RemoveCVRef:
+    case UnaryTransformType::RemovePointer:
+    case UnaryTransformType::RemoveReference:
+    case UnaryTransformType::RemoveVolatile:
       return;
   }
 
Index: clang/lib/AST/TextNodeDumper.cpp
===================================================================
--- clang/lib/AST/TextNodeDumper.cpp
+++ clang/lib/AST/TextNodeDumper.cpp
@@ -1547,6 +1547,42 @@
   case UnaryTransformType::EnumUnderlyingType:
     OS << " underlying_type";
     break;
+  case UnaryTransformType::AddConst:
+    OS << " add_const";
+    break;
+  case UnaryTransformType::AddCV:
+    OS << " add_cv";
+    break;
+  case UnaryTransformType::AddLvalueReference:
+    OS << " add_lvalue_reference";
+    break;
+  case UnaryTransformType::AddPointer:
+    OS << " add_pointer";
+    break;
+  case UnaryTransformType::AddRvalueReference:
+    OS << " add_rvalue_reference";
+    break;
+  case UnaryTransformType::AddVolatile:
+    OS << " add_volatile";
+    break;
+  case UnaryTransformType::RemoveConst:
+    OS << " remove_const";
+    break;
+  case UnaryTransformType::RemoveCV:
+    OS << " remove_cv";
+    break;
+  case UnaryTransformType::RemoveCVRef:
+    OS << " remove_cvref";
+    break;
+  case UnaryTransformType::RemovePointer:
+    OS << " remove_pointer";
+    break;
+  case UnaryTransformType::RemoveReference:
+    OS << " remove_reference";
+    break;
+  case UnaryTransformType::RemoveVolatile:
+    OS << " remove_volatile";
+    break;
   }
 }
 
Index: clang/lib/AST/JSONNodeDumper.cpp
===================================================================
--- clang/lib/AST/JSONNodeDumper.cpp
+++ clang/lib/AST/JSONNodeDumper.cpp
@@ -665,6 +665,42 @@
   case UnaryTransformType::EnumUnderlyingType:
     JOS.attribute("transformKind", "underlying_type");
     break;
+  case UnaryTransformType::AddConst:
+    JOS.attribute("transformedKind", "add_const");
+    break;
+  case UnaryTransformType::AddCV:
+    JOS.attribute("transformedKind", "add_cv");
+    break;
+  case UnaryTransformType::AddLvalueReference:
+    JOS.attribute("transformedKind", "add_lvalue_reference");
+    break;
+  case UnaryTransformType::AddPointer:
+    JOS.attribute("transformedKind", "add_pointer");
+    break;
+  case UnaryTransformType::AddRvalueReference:
+    JOS.attribute("transformedKind", "add_rvalue_reference");
+    break;
+  case UnaryTransformType::AddVolatile:
+    JOS.attribute("transformedKind", "add_volatile");
+    break;
+  case UnaryTransformType::RemoveConst:
+    JOS.attribute("transformedKind", "remove_const");
+    break;
+  case UnaryTransformType::RemoveCV:
+    JOS.attribute("transformedKind", "remove_cv");
+    break;
+  case UnaryTransformType::RemoveCVRef:
+    JOS.attribute("transformedKind", "remove_cvref");
+    break;
+  case UnaryTransformType::RemovePointer:
+    JOS.attribute("transformedKind", "remove_pointer");
+    break;
+  case UnaryTransformType::RemoveReference:
+    JOS.attribute("transformedKind", "remove_reference");
+    break;
+  case UnaryTransformType::RemoveVolatile:
+    JOS.attribute("transformedKind", "remove_volatile");
+    break;
   }
 }
 
Index: clang/lib/AST/ItaniumMangle.cpp
===================================================================
--- clang/lib/AST/ItaniumMangle.cpp
+++ clang/lib/AST/ItaniumMangle.cpp
@@ -3925,6 +3925,42 @@
       case UnaryTransformType::EnumUnderlyingType:
         Out << "3eut";
         break;
+      case UnaryTransformType::AddConst:
+        Out << "2ac";
+        break;
+      case UnaryTransformType::AddCV:
+        Out << "3acv";
+        break;
+      case UnaryTransformType::AddLvalueReference:
+        Out << "5alref";
+        break;
+      case UnaryTransformType::AddPointer:
+        Out << "4aptr";
+        break;
+      case UnaryTransformType::AddRvalueReference:
+        Out << "5arref";
+        break;
+      case UnaryTransformType::AddVolatile:
+        Out << "3av";
+        break;
+      case UnaryTransformType::RemoveConst:
+        Out << "3rc";
+        break;
+      case UnaryTransformType::RemoveCV:
+        Out << "3rcv";
+        break;
+      case UnaryTransformType::RemoveCVRef:
+        Out << "4rcvr";
+        break;
+      case UnaryTransformType::RemovePointer:
+        Out << "4rptr";
+        break;
+      case UnaryTransformType::RemoveReference:
+        Out << "2rr";
+        break;
+      case UnaryTransformType::RemoveVolatile:
+        Out << "2rv";
+        break;
     }
   }
 
Index: clang/lib/AST/ASTContext.cpp
===================================================================
--- clang/lib/AST/ASTContext.cpp
+++ clang/lib/AST/ASTContext.cpp
@@ -5601,6 +5601,7 @@
 
 /// getUnaryTransformationType - We don't unique these, since the memory
 /// savings are minimal and these are rare.
+// Update 2021-12-16: it might be worth revisiting this
 QualType ASTContext::getUnaryTransformType(QualType BaseType,
                                            QualType UnderlyingType,
                                            UnaryTransformType::UTTKind Kind)
Index: clang/include/clang/Sema/DeclSpec.h
===================================================================
--- clang/include/clang/Sema/DeclSpec.h
+++ clang/include/clang/Sema/DeclSpec.h
@@ -291,6 +291,19 @@
   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_add_const = clang::TST_add_const;
+  static const TST TST_add_cv = clang::TST_add_cv;
+  static const TST TST_add_lvalue_reference = clang::TST_add_lvalue_reference;
+  static const TST TST_add_pointer = clang::TST_add_pointer;
+  static const TST TST_add_rvalue_reference = clang::TST_add_rvalue_reference;
+  static const TST TST_add_volatile = clang::TST_add_volatile;
+  static const TST TST_decay = clang::TST_decay;
+  static const TST TST_remove_const = clang::TST_remove_const;
+  static const TST TST_remove_cv = clang::TST_remove_cv;
+  static const TST TST_remove_cvref = clang::TST_remove_cvref;
+  static const TST TST_remove_pointer = clang::TST_remove_pointer;
+  static const TST TST_remove_reference = clang::TST_remove_reference;
+  static const TST TST_remove_volatile = clang::TST_remove_volatile;
   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;
Index: clang/include/clang/Parse/Parser.h
===================================================================
--- clang/include/clang/Parse/Parser.h
+++ clang/include/clang/Parse/Parser.h
@@ -3034,6 +3034,8 @@
          SourceLocation &EllipsisLoc);
   void ParseBracketDeclarator(Declarator &D);
   void ParseMisplacedBracketDeclarator(Declarator &D);
+  void ParseTypeTransformTypeSpecifier(DeclSpec &DS);
+  DeclSpec::TST TypeTransformTokToDeclSpec();
 
   //===--------------------------------------------------------------------===//
   // C++ 7: Declarations [dcl.dcl]
Index: clang/include/clang/Basic/TokenKinds.def
===================================================================
--- clang/include/clang/Basic/TokenKinds.def
+++ clang/include/clang/Basic/TokenKinds.def
@@ -508,6 +508,19 @@
 TYPE_TRAIT_1(__has_unique_object_representations,
              HasUniqueObjectRepresentations, KEYCXX)
 KEYWORD(__underlying_type           , KEYCXX)
+KEYWORD(__add_const, KEYCXX)
+KEYWORD(__add_cv, KEYCXX)
+KEYWORD(__add_lvalue_reference, KEYCXX)
+KEYWORD(__add_pointer, KEYCXX)
+KEYWORD(__add_rvalue_reference, KEYCXX)
+KEYWORD(__add_volatile, KEYCXX)
+KEYWORD(__decay, KEYCXX)
+KEYWORD(__remove_const, KEYCXX)
+KEYWORD(__remove_cv, KEYCXX)
+KEYWORD(__remove_cvref, KEYCXX)
+KEYWORD(__remove_pointer, KEYCXX)
+KEYWORD(__remove_reference, KEYCXX)
+KEYWORD(__remove_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
@@ -53,41 +53,54 @@
     TST_unspecified,
     TST_void,
     TST_char,
-    TST_wchar,        // C++ wchar_t
-    TST_char8,        // C++20 char8_t (proposed)
-    TST_char16,       // C++11 char16_t
-    TST_char32,       // C++11 char32_t
+    TST_wchar,  // C++ wchar_t
+    TST_char8,  // C++20 char8_t (proposed)
+    TST_char16, // C++11 char16_t
+    TST_char32, // C++11 char32_t
     TST_int,
     TST_int128,
-    TST_bitint,       // Bit-precise integer types.
-    TST_half,         // OpenCL half, ARM NEON __fp16
-    TST_Float16,      // C11 extension ISO/IEC TS 18661-3
-    TST_Accum,        // ISO/IEC JTC1 SC22 WG14 N1169 Extension
+    TST_bitint,  // Bit-precise integer types.
+    TST_half,    // OpenCL half, ARM NEON __fp16
+    TST_Float16, // C11 extension ISO/IEC TS 18661-3
+    TST_Accum,   // ISO/IEC JTC1 SC22 WG14 N1169 Extension
     TST_Fract,
     TST_BFloat16,
     TST_float,
     TST_double,
     TST_float128,
     TST_ibm128,
-    TST_bool,         // _Bool
-    TST_decimal32,    // _Decimal32
-    TST_decimal64,    // _Decimal64
-    TST_decimal128,   // _Decimal128
+    TST_bool,       // _Bool
+    TST_decimal32,  // _Decimal32
+    TST_decimal64,  // _Decimal64
+    TST_decimal128, // _Decimal128
     TST_enum,
     TST_union,
     TST_struct,
-    TST_class,        // C++ class type
-    TST_interface,    // C++ (Microsoft-specific) __interface type
-    TST_typename,     // Typedef, C++ class-name or enum name, etc.
+    TST_class,     // C++ class type
+    TST_interface, // C++ (Microsoft-specific) __interface type
+    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_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
+    TST_decltype,             // C++11 decltype
+    TST_underlyingType,       // __underlying_type for C++11
+    TST_add_const,            // __add_const extension
+    TST_add_cv,               // __add_cv extension
+    TST_add_lvalue_reference, // __add_add_lvalue_reference extension
+    TST_add_pointer,          // __add_pointer extension
+    TST_add_rvalue_reference, // __add_add_rvalue_reference extension
+    TST_add_volatile,         // __add_volatile extension
+    TST_decay,                // __decay extension
+    TST_remove_const,         // __remove_const extension
+    TST_remove_cv,            // __remove_cv extension
+    TST_remove_cvref,         // __remove_cvref extension
+    TST_remove_pointer,       // __remove_pointer extension
+    TST_remove_reference,     // __remove_reference extension
+    TST_remove_volatile,      // __remove_volatile extension
+    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
Index: clang/include/clang/AST/Type.h
===================================================================
--- clang/include/clang/AST/Type.h
+++ clang/include/clang/AST/Type.h
@@ -740,6 +740,8 @@
     return Value.getPointer().isNull();
   }
 
+  bool isReferenceable() const;
+
   /// Determine whether this particular QualType instance has the
   /// "const" qualifier set, without looking through typedefs that may have
   /// added "const" at a different level.
@@ -4553,7 +4555,20 @@
 class UnaryTransformType : public Type {
 public:
   enum UTTKind {
-    EnumUnderlyingType
+    EnumUnderlyingType,
+    AddCV,
+    AddConst,
+    AddLvalueReference,
+    AddPointer,
+    AddRvalueReference,
+    AddVolatile,
+    Decay,
+    RemoveConst,
+    RemoveCV,
+    RemoveCVRef,
+    RemovePointer,
+    RemoveReference,
+    RemoveVolatile,
   };
 
 private:
@@ -6455,6 +6470,21 @@
   return (isNull() ? nullptr : getCommonPtr()->BaseType);
 }
 
+inline bool QualType::isReferenceable() const {
+  // C++ [defns.referenceable]
+  //   type that is either an object type, a function type that does not have
+  //   cv-qualifiers or a ref-qualifier, or a reference type
+  const Type &Self = **this;
+  if (Self.isObjectType() || Self.isReferenceType())
+    return true;
+  if (!Self.isFunctionType())
+    return false;
+
+  const auto *F = Self.getAs<FunctionProtoType>();
+  return F == nullptr ||
+         (F->getMethodQuals().empty() && F->getRefQualifier() == RQ_None);
+}
+
 inline SplitQualType QualType::split() const {
   if (!hasLocalNonFastQualifiers())
     return SplitQualType(getTypePtrUnsafe(),
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to