Index: clang/include/clang/AST/Type.h =================================================================== --- clang/include/clang/AST/Type.h +++ clang/include/clang/AST/Type.h @@ -4366,7 +4366,13 @@ EnumUnderlyingType, RemoveReferenceType, AddRValueType, - AddLValueType + AddLValueType, + RemoveCV, + RemoveConst, + RemoveVolatile, + AddCV, + AddConst, + AddVolatile }; private: Index: clang/include/clang/Basic/Specifiers.h =================================================================== --- clang/include/clang/Basic/Specifiers.h +++ clang/include/clang/Basic/Specifiers.h @@ -91,6 +91,12 @@ 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/Basic/TokenKinds.def =================================================================== --- clang/include/clang/Basic/TokenKinds.def +++ clang/include/clang/Basic/TokenKinds.def @@ -490,6 +490,12 @@ 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/Parse/Parser.h =================================================================== --- clang/include/clang/Parse/Parser.h +++ clang/include/clang/Parse/Parser.h @@ -2602,8 +2602,8 @@ SourceLocation StartLoc, SourceLocation EndLoc); void ParseUnderlyingTypeSpecifier(DeclSpec &DS); - DeclSpec::TST ReferenceTransformTokToDeclSpec(); - void ParseAddReferenceTypeSpecifier(DeclSpec &DS); + DeclSpec::TST TypeTransformTokToDeclSpec(); + void ParseTypeTransformTypeSpecifier(DeclSpec &DS); void ParseAtomicSpecifier(DeclSpec &DS); ExprResult ParseAlignArgument(SourceLocation Start, Index: clang/include/clang/Sema/DeclSpec.h =================================================================== --- clang/include/clang/Sema/DeclSpec.h +++ clang/include/clang/Sema/DeclSpec.h @@ -303,6 +303,12 @@ 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; @@ -413,7 +419,9 @@ return (T == TST_typename || T == TST_typeofType || T == TST_underlyingType || T == TST_atomic|| T == TST_addLValueReferenceType || T == TST_addRValueReferenceType || - T == TST_removeReferenceType); + 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/lib/Format/FormatToken.cpp =================================================================== --- clang/lib/Format/FormatToken.cpp +++ clang/lib/Format/FormatToken.cpp @@ -58,6 +58,12 @@ 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/lib/Lex/PPMacroExpansion.cpp =================================================================== --- clang/lib/Lex/PPMacroExpansion.cpp +++ clang/lib/Lex/PPMacroExpansion.cpp @@ -1639,6 +1639,12 @@ .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(II->getName()) Index: clang/lib/Parse/ParseDecl.cpp =================================================================== --- clang/lib/Parse/ParseDecl.cpp +++ clang/lib/Parse/ParseDecl.cpp @@ -3922,7 +3922,13 @@ case tok::kw___remove_reference: case tok::kw___add_rvalue_reference: case tok::kw___add_lvalue_reference: - ParseAddReferenceTypeSpecifier(DS); + 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: Index: clang/lib/Parse/ParseDeclCXX.cpp =================================================================== --- clang/lib/Parse/ParseDeclCXX.cpp +++ clang/lib/Parse/ParseDeclCXX.cpp @@ -1083,7 +1083,7 @@ DS.setTypeofParensRange(T.getRange()); } -DeclSpec::TST Parser::ReferenceTransformTokToDeclSpec() { +DeclSpec::TST Parser::TypeTransformTokToDeclSpec() { switch (Tok.getKind()) { case tok::kw___add_lvalue_reference: return DeclSpec::TST_addLValueReferenceType; @@ -1091,13 +1091,25 @@ 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::ParseAddReferenceTypeSpecifier(DeclSpec &DS) { - DeclSpec::TST ReferenceTransformTST = ReferenceTransformTokToDeclSpec(); +void Parser::ParseTypeTransformTypeSpecifier(DeclSpec &DS) { + DeclSpec::TST TypeTransformTST = TypeTransformTokToDeclSpec(); SourceLocation StartLoc = ConsumeToken(); BalancedDelimiterTracker T(*this, tok::l_paren); @@ -1116,7 +1128,7 @@ const char *PrevSpec; unsigned DiagID; - if (DS.SetTypeSpecType(ReferenceTransformTST, + if (DS.SetTypeSpecType(TypeTransformTST, StartLoc, PrevSpec, DiagID, BaseTyResult.get(), Actions.getASTContext().getPrintingPolicy())) { Index: clang/lib/Sema/DeclSpec.cpp =================================================================== --- clang/lib/Sema/DeclSpec.cpp +++ clang/lib/Sema/DeclSpec.cpp @@ -377,6 +377,12 @@ 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(); @@ -559,6 +565,12 @@ 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/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -144,6 +144,12 @@ 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; @@ -5290,6 +5296,12 @@ 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/SemaTemplateVariadic.cpp =================================================================== --- clang/lib/Sema/SemaTemplateVariadic.cpp +++ clang/lib/Sema/SemaTemplateVariadic.cpp @@ -841,6 +841,12 @@ 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/SemaType.cpp =================================================================== --- clang/lib/Sema/SemaType.cpp +++ clang/lib/Sema/SemaType.cpp @@ -1262,6 +1262,18 @@ 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"); } @@ -1612,6 +1624,12 @@ 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."); @@ -8429,6 +8447,46 @@ 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/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 +struct remove_const +{ + typedef __remove_const(T) type; +}; + +template +struct remove_volatile +{ + typedef __remove_volatile(T) type; +}; + +template +struct remove_cv +{ + typedef __remove_cv(T) type; +}; + +template +struct add_const +{ + typedef __add_const(T) type; +}; + +template +struct add_volatile +{ + typedef __add_volatile(T) type; +}; + +template +struct add_cv +{ + typedef __add_cv(T) type; +}; + +template +struct test +{ + static const bool value = + __is_same(typename remove_const::type, T) && + __is_same(typename remove_const::type, volatile T) && + __is_same(typename remove_const::type, T) && + + __is_same(typename remove_volatile::type, T) && + __is_same(typename remove_volatile::type, const T) && + __is_same(typename remove_volatile::type, T) && + + __is_same(typename remove_cv::type, T) && + __is_same(typename remove_cv::type, T) && + __is_same(typename remove_cv::type, T) && + __is_same(typename remove_cv::type, T) && + + __is_same(typename add_const::type, const T) && + __is_same(typename add_const::type, const volatile T) && + __is_same(typename add_const::type, const T) && + + __is_same(typename add_volatile::type, volatile T) && + __is_same(typename add_volatile::type, const volatile T) && + __is_same(typename add_volatile::type, volatile T) && + + __is_same(typename add_cv::type, const volatile T) && + __is_same(typename add_cv::type, const volatile T) && + __is_same(typename add_cv::type, const volatile T) && + __is_same(typename add_cv::type, const volatile T); +}; + +struct Foo { }; + +template +struct Bar { }; + +template +class Baz { }; + +static_assert(test::value, ""); +static_assert(test::value, ""); +static_assert(test::value, ""); +static_assert(test::value, ""); +static_assert(test>::value, ""); +static_assert(test>::value, ""); 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 + +#include "test_macros.h" +#include "template_cost_testing.h" + +template struct Arg { enum { value = 1 }; }; + +#ifdef TEST_NEW + +template +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: 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 + +#include "test_macros.h" +#include "template_cost_testing.h" + +template struct Arg { enum { value = 1 }; }; + +#ifdef TEST_NEW + +template +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); +} + +