diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -4553,7 +4553,15 @@ class UnaryTransformType : public Type { public: enum UTTKind { - EnumUnderlyingType + EnumUnderlyingType, + AddCV, + AddConst, + AddVolatile, + RemoveConst, + RemoveCV, + RemoveCVRef, + RemoveReference, + RemoveVolatile, }; private: diff --git a/clang/include/clang/Basic/Specifiers.h b/clang/include/clang/Basic/Specifiers.h --- a/clang/include/clang/Basic/Specifiers.h +++ b/clang/include/clang/Basic/Specifiers.h @@ -53,41 +53,49 @@ 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_add_const, // __add_const extension + TST_add_cv, // __add_cv extension + TST_add_volatile, // __add_volatile extension + TST_remove_const, // __remove_const extension + TST_remove_cv, // __remove_cv extension + TST_remove_cvref, // __remove_cvref 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 + TST_atomic, // C11 _Atomic, #define GENERIC_IMAGE_TYPE(ImgType, Id) TST_##ImgType##_t, // OpenCL image types #include "clang/Basic/OpenCLImageTypes.def" TST_error // erroneous type diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -508,6 +508,14 @@ TYPE_TRAIT_1(__has_unique_object_representations, HasUniqueObjectRepresentations, KEYCXX) KEYWORD(__underlying_type , KEYCXX) +KEYWORD(__add_const, KEYCXX) +KEYWORD(__add_cv, KEYCXX) +KEYWORD(__add_volatile, KEYCXX) +KEYWORD(__remove_const, KEYCXX) +KEYWORD(__remove_cv, KEYCXX) +KEYWORD(__remove_cvref, KEYCXX) +KEYWORD(__remove_reference, KEYCXX) +KEYWORD(__remove_volatile, KEYCXX) // Clang-only C++ Type Traits TYPE_TRAIT_2(__reference_binds_to_temporary, ReferenceBindsToTemporary, KEYCXX) diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -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] diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -291,6 +291,14 @@ 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_volatile = clang::TST_add_volatile; + 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_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; diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -3925,6 +3925,30 @@ case UnaryTransformType::EnumUnderlyingType: Out << "3eut"; break; + case UnaryTransformType::AddConst: + Out << "3ac"; + break; + case UnaryTransformType::AddCV: + Out << "3acv"; + break; + case UnaryTransformType::AddVolatile: + Out << "3av"; + break; + case UnaryTransformType::RemoveConst: + Out << "3rc"; + break; + case UnaryTransformType::RemoveCV: + Out << "3rcv"; + break; + case UnaryTransformType::RemoveCVRef: + Out << "3rcvr"; + break; + case UnaryTransformType::RemoveReference: + Out << "3rr"; + break; + case UnaryTransformType::RemoveVolatile: + Out << "3rv"; + break; } } diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp --- a/clang/lib/AST/JSONNodeDumper.cpp +++ b/clang/lib/AST/JSONNodeDumper.cpp @@ -665,6 +665,30 @@ 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::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::RemoveReference: + JOS.attribute("transformedKind", "remove_reference"); + break; + case UnaryTransformType::RemoveVolatile: + JOS.attribute("transformedKind", "remove_volatile"); + break; } } diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -1547,6 +1547,30 @@ case UnaryTransformType::EnumUnderlyingType: OS << " underlying_type"; break; + case UnaryTransformType::AddConst: + OS << " add_const"; + break; + case UnaryTransformType::AddCV: + OS << " add_cv"; + 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::RemoveReference: + OS << " remove_reference"; + break; + case UnaryTransformType::RemoveVolatile: + OS << " remove_volatile"; + break; } } diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -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" @@ -1119,11 +1120,24 @@ switch (T->getUTTKind()) { case UnaryTransformType::EnumUnderlyingType: - OS << "__underlying_type("; + case UnaryTransformType::AddConst: + case UnaryTransformType::AddCV: + case UnaryTransformType::AddVolatile: + case UnaryTransformType::RemoveConst: + case UnaryTransformType::RemoveCV: + case UnaryTransformType::RemoveCVRef: + case UnaryTransformType::RemoveReference: + case UnaryTransformType::RemoveVolatile: { + constexpr std::array Transformation = { + "__underlying_type", "__add_const", "__add_cv", + "__add_volatile", "__remove_const", "__remove_cv", + "__remove_cvref", "__remove_reference", "__remove_volatile"}; + OS << Transformation[T->getUTTKind()] << '('; print(T->getBaseType(), OS, StringRef()); OS << ')'; spaceBeforePlaceHolder(OS); return; + } } printBefore(T->getBaseType(), OS); @@ -1135,6 +1149,14 @@ switch (T->getUTTKind()) { case UnaryTransformType::EnumUnderlyingType: + case UnaryTransformType::AddConst: + case UnaryTransformType::AddCV: + case UnaryTransformType::AddVolatile: + case UnaryTransformType::RemoveConst: + case UnaryTransformType::RemoveCV: + case UnaryTransformType::RemoveCVRef: + case UnaryTransformType::RemoveReference: + case UnaryTransformType::RemoveVolatile: return; } diff --git a/clang/lib/Format/FormatToken.cpp b/clang/lib/Format/FormatToken.cpp --- a/clang/lib/Format/FormatToken.cpp +++ b/clang/lib/Format/FormatToken.cpp @@ -57,6 +57,14 @@ 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___remove_const: + case tok::kw___remove_cv: + case tok::kw___remove_cvref: + case tok::kw___remove_reference: + case tok::kw___remove_volatile: case tok::annot_typename: case tok::kw_char8_t: case tok::kw_char16_t: diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -1658,6 +1658,14 @@ .Case("__array_extent", true) .Case("__reference_binds_to_temporary", true) .Case("__underlying_type", true) + .Case("__add_const", true) + .Case("__add_cv", true) + .Case("__add_volatile", true) + .Case("__remove_const", true) + .Case("__remove_cv", true) + .Case("__remove_cvref", true) + .Case("__remove_reference", true) + .Case("__remove_volatile", true) .Default(false); } else { return llvm::StringSwitch(II->getName()) diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -4115,6 +4115,17 @@ ParseUnderlyingTypeSpecifier(DS); continue; + case tok::kw___add_const: + case tok::kw___add_cv: + case tok::kw___add_volatile: + 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: + 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 +4226,57 @@ } } +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_volatile: + return DeclSpec::TST_add_volatile; + 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_reference: + return DeclSpec::TST_remove_reference; + case tok::kw___remove_volatile: + return DeclSpec::TST_remove_volatile; + } + + __builtin_unreachable(); +} + +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. /// diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -1508,61 +1508,68 @@ // 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_volatile, + 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_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 diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/lib/Sema/DeclSpec.cpp @@ -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,14 @@ return false; case TST_underlyingType: + case TST_add_const: + case TST_add_cv: + case TST_add_volatile: + case TST_remove_const: + case TST_remove_cv: + case TST_remove_cvref: + case TST_remove_reference: + case TST_remove_volatile: case TST_typename: case TST_typeofType: { QualType QT = DS.getRepAsType().get(); @@ -577,6 +586,14 @@ 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_volatile: return "__add_volatile"; + 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_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"; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -145,6 +145,14 @@ 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___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 +5607,14 @@ 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_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; diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp --- a/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -861,6 +861,14 @@ case TST_typename: case TST_typeofType: case TST_underlyingType: + case TST_add_const: + case TST_add_cv: + case TST_add_volatile: + case TST_remove_const: + case TST_remove_cv: + case TST_remove_cvref: + case TST_remove_reference: + case TST_remove_volatile: case TST_atomic: { QualType T = DS.getRepAsType().get(); if (!T.isNull() && T->containsUnexpandedParameterPack()) diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -22,6 +22,7 @@ #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 +1258,32 @@ 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_volatile: + return UnaryTransformType::AddVolatile; + case TST_remove_const: + return UnaryTransformType::RemoveConst; + case TST_remove_cv: + return UnaryTransformType::RemoveCV; + case TST_remove_cvref: + return UnaryTransformType::RemoveCVRef; + 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 +1667,22 @@ break; } case DeclSpec::TST_underlyingType: + case DeclSpec::TST_add_const: + case DeclSpec::TST_add_cv: + case DeclSpec::TST_add_volatile: + 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: 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 +6010,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 +9102,53 @@ return Context.getUnaryTransformType(BaseType, Underlying, UnaryTransformType::EnumUnderlyingType); } + 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; + switch (UKind) { + case UnaryTransformType::AddConst: + Quals.addConst(); + break; + case UnaryTransformType::AddCV: + Quals.addConst(); + [[fallthrough]]; + case UnaryTransformType::AddVolatile: + Quals.addVolatile(); + break; + case UnaryTransformType::RemoveConst: + Quals.removeConst(); + break; + case UnaryTransformType::RemoveCV: + Quals.removeConst(); + [[fallthrough]]; + case UnaryTransformType::RemoveVolatile: + Quals.removeVolatile(); + break; + } + QualType Underlying(Split.Ty, Quals.getAsOpaqueValue()); + return Context.getUnaryTransformType(BaseType, Underlying, UKind); + } } llvm_unreachable("unknown unary transform type"); } diff --git a/clang/test/SemaCXX/add_cv.cpp b/clang/test/SemaCXX/add_cv.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaCXX/add_cv.cpp @@ -0,0 +1,41 @@ +// RUN: %clang_cc1 -std=c++11 %s + +template +using add_const_t = __add_const(T); + +template +constexpr bool check_add_cv() { + static_assert(__is_same(__add_const(T), const T), ""); + static_assert(__is_same(__add_volatile(T), volatile T), ""); + static_assert(__is_same(__add_cv(T), const volatile T), ""); + return true; +} + +static_assert(check_add_cv(), ""); +static_assert(check_add_cv(), ""); +static_assert(check_add_cv(), ""); +static_assert(check_add_cv(), ""); +static_assert(check_add_cv(), ""); +static_assert(check_add_cv(), ""); +static_assert(check_add_cv(), ""); +static_assert(check_add_cv(), ""); +static_assert(check_add_cv(), ""); +static_assert(check_add_cv(), ""); + +struct S {}; +static_assert(check_add_cv(), ""); +static_assert(check_add_cv(), ""); +static_assert(check_add_cv(), ""); +static_assert(check_add_cv(), ""); +static_assert(check_add_cv(), ""); +static_assert(check_add_cv(), ""); +static_assert(check_add_cv(), ""); +static_assert(check_add_cv(), ""); +static_assert(check_add_cv(), ""); +static_assert(check_add_cv(), ""); +static_assert(check_add_cv(), ""); +static_assert(check_add_cv(), ""); +static_assert(check_add_cv(), ""); +static_assert(check_add_cv(), ""); +static_assert(check_add_cv(), ""); +static_assert(check_add_cv(), ""); diff --git a/clang/test/SemaCXX/remove_cvref.cpp b/clang/test/SemaCXX/remove_cvref.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaCXX/remove_cvref.cpp @@ -0,0 +1,86 @@ +// RUN: %clang_cc1 -std=c++11 %s + +template +struct check_remove_reference { + constexpr check_remove_reference() { + static_assert(__is_same(__remove_reference(T &), T), ""); + static_assert(__is_same(__remove_reference(const T &), const T), ""); + static_assert(__is_same(__remove_reference(volatile T &), volatile T), ""); + static_assert(__is_same(__remove_reference(const volatile T &), const volatile T), ""); + + static_assert(__is_same(__remove_reference(T &&), T), ""); + static_assert(__is_same(__remove_reference(const T &&), const T), ""); + static_assert(__is_same(__remove_reference(volatile T &&), volatile T), ""); + static_assert(__is_same(__remove_reference(const volatile T &&), const volatile T), ""); + + static_assert(__is_same(__remove_cvref(T &), T), ""); + static_assert(__is_same(__remove_cvref(const T &), T), ""); + static_assert(__is_same(__remove_cvref(volatile T &), T), ""); + static_assert(__is_same(__remove_cvref(const volatile T &), T), ""); + + static_assert(__is_same(__remove_cvref(T &&), T), ""); + static_assert(__is_same(__remove_cvref(const T &&), T), ""); + static_assert(__is_same(__remove_cvref(volatile T &&), T), ""); + static_assert(__is_same(__remove_cvref(const volatile T &&), T), ""); + } +}; + +template <> struct check_remove_reference {}; +template struct check_remove_reference {}; +template struct check_remove_reference {}; + +template +constexpr bool check_remove_qualifiers() { + static_assert(__is_same(__remove_const(const T), T), ""); + static_assert(__is_same(__remove_const(volatile T), volatile T), ""); + static_assert(__is_same(__remove_const(const volatile T), volatile T), ""); + + static_assert(__is_same(__remove_volatile(const T), const T), ""); + static_assert(__is_same(__remove_volatile(volatile T), T), ""); + static_assert(__is_same(__remove_volatile(const volatile T), const T), ""); + + static_assert(__is_same(__remove_cv(const T), T), ""); + static_assert(__is_same(__remove_cv(volatile T), T), ""); + static_assert(__is_same(__remove_cv(const volatile T), T), ""); + + check_remove_reference(); + + return true; +} + +static_assert(check_remove_qualifiers(), ""); +static_assert(check_remove_qualifiers(), ""); +static_assert(check_remove_qualifiers(), ""); +static_assert(check_remove_qualifiers(), ""); +static_assert(check_remove_qualifiers(), ""); +static_assert(check_remove_qualifiers(), ""); +static_assert(check_remove_qualifiers(), ""); +static_assert(check_remove_qualifiers(), ""); +static_assert(check_remove_qualifiers(), ""); +static_assert(check_remove_qualifiers(), ""); +static_assert(check_remove_qualifiers(), ""); +static_assert(check_remove_qualifiers(), ""); +static_assert(check_remove_qualifiers(), ""); +static_assert(check_remove_qualifiers(), ""); +static_assert(check_remove_qualifiers(), ""); +static_assert(check_remove_qualifiers(), ""); +static_assert(check_remove_qualifiers(), ""); + +struct S {}; +static_assert(check_remove_qualifiers(), ""); +static_assert(check_remove_qualifiers(), ""); +static_assert(check_remove_qualifiers(), ""); +static_assert(check_remove_qualifiers(), ""); +static_assert(check_remove_qualifiers(), ""); +static_assert(check_remove_qualifiers(), ""); +static_assert(check_remove_qualifiers(), ""); +static_assert(check_remove_qualifiers(), ""); +static_assert(check_remove_qualifiers(), ""); +static_assert(check_remove_qualifiers(), ""); +static_assert(check_remove_qualifiers(), ""); +static_assert(check_remove_qualifiers(), ""); +static_assert(check_remove_qualifiers(), ""); +static_assert(check_remove_qualifiers(), ""); +static_assert(check_remove_qualifiers(), ""); +static_assert(check_remove_qualifiers(), ""); +static_assert(check_remove_qualifiers(), "");