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 @@ -4554,6 +4554,7 @@ public: enum UTTKind { EnumUnderlyingType, + AddCV, AddConst, AddVolatile, }; 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 @@ -84,6 +84,7 @@ 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_auto, // C++11 auto TST_decltype_auto, // C++1y decltype(auto) 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 @@ -509,6 +509,7 @@ HasUniqueObjectRepresentations, KEYCXX) KEYWORD(__underlying_type , KEYCXX) KEYWORD(__add_const, KEYCXX) +KEYWORD(__add_cv, KEYCXX) KEYWORD(__add_volatile, KEYCXX) // Clang-only C++ Type Traits 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 @@ -292,6 +292,7 @@ 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_auto = clang::TST_auto; static const TST TST_auto_type = clang::TST_auto_type; 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 @@ -3928,6 +3928,9 @@ case UnaryTransformType::AddConst: Out << "3ac"; break; + case UnaryTransformType::AddCV: + Out << "3acv"; + break; case UnaryTransformType::AddVolatile: Out << "3av"; 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 @@ -668,6 +668,9 @@ 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; 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 @@ -1121,9 +1121,10 @@ switch (T->getUTTKind()) { case UnaryTransformType::EnumUnderlyingType: case UnaryTransformType::AddConst: + case UnaryTransformType::AddCV: case UnaryTransformType::AddVolatile: { - constexpr std::array Transformation = { - "__underlying_type", "__add_const", "__add_volatile"}; + constexpr std::array Transformation = { + "__underlying_type", "__add_const", "__add_cv", "__add_volatile"}; OS << Transformation[T->getUTTKind()] << '('; print(T->getBaseType(), OS, StringRef()); OS << ')'; @@ -1142,6 +1143,7 @@ switch (T->getUTTKind()) { case UnaryTransformType::EnumUnderlyingType: case UnaryTransformType::AddConst: + case UnaryTransformType::AddCV: case UnaryTransformType::AddVolatile: 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 @@ -58,6 +58,7 @@ 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::annot_typename: case tok::kw_char8_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 @@ -1659,6 +1659,7 @@ .Case("__reference_binds_to_temporary", true) .Case("__underlying_type", true) .Case("__add_const", true) + .Case("__add_cv", true) .Case("__add_volatile", true) .Default(false); } else { 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 @@ -4116,6 +4116,7 @@ continue; case tok::kw___add_const: + case tok::kw___add_cv: case tok::kw___add_volatile: ParseTypeTransformTypeSpecifier(DS); continue; @@ -4224,6 +4225,8 @@ 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; } 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 @@ -1511,14 +1511,15 @@ if (TagType == DeclSpec::TST_struct && Tok.isNot(tok::identifier) && !Tok.isAnnotation() && Tok.getIdentifierInfo() && Tok.isOneOf( - tok::kw___add_const, 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___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, 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 @@ -391,6 +391,7 @@ case TST_underlyingType: case TST_add_const: + case TST_add_cv: case TST_add_volatile: case TST_typename: case TST_typeofType: { @@ -581,6 +582,8 @@ 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_unknown_anytype: return "__unknown_anytype"; 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 @@ -146,6 +146,7 @@ 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___auto_type: return true; @@ -5602,6 +5603,7 @@ 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_atomic: { // Grab the type from the parser. 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 @@ -862,6 +862,7 @@ case TST_typeofType: case TST_underlyingType: case TST_add_const: + case TST_add_cv: case TST_add_volatile: case TST_atomic: { QualType T = DS.getRepAsType().get(); 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 @@ -1262,6 +1262,8 @@ 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_underlyingType: @@ -1655,6 +1657,7 @@ } case DeclSpec::TST_underlyingType: case DeclSpec::TST_add_const: + case DeclSpec::TST_add_cv: case DeclSpec::TST_add_volatile: Result = S.GetTypeFromParser(DS.getRepAsType()); assert(!Result.isNull() && "Didn't get a type for the transformation?"); @@ -9083,25 +9086,25 @@ return Context.getUnaryTransformType(BaseType, Underlying, UnaryTransformType::EnumUnderlyingType); } - case UnaryTransformType::AddConst: { - SplitQualType Split = BaseType.getSplitUnqualifiedType(); - Qualifiers Quals = BaseType.getQualifiers(); - if (BaseType->isReferenceType() || BaseType->isFunctionType()) - return BaseType; - Quals.addConst(); - QualType Underlying(Split.Ty, Quals.getAsOpaqueValue()); - return Context.getUnaryTransformType(BaseType, Underlying, - UnaryTransformType::AddConst); - } + case UnaryTransformType::AddConst: + case UnaryTransformType::AddCV: case UnaryTransformType::AddVolatile: { SplitQualType Split = BaseType.getSplitUnqualifiedType(); Qualifiers Quals = BaseType.getQualifiers(); if (BaseType->isReferenceType() || BaseType->isFunctionType()) return BaseType; - Quals.addVolatile(); + switch (UKind) { + case UnaryTransformType::AddConst: + Quals.addConst(); + break; + case UnaryTransformType::AddCV: + Quals.addConst(); + [[fallthrough]]; + case UnaryTransformType::AddVolatile: + Quals.addVolatile(); + } QualType Underlying(Split.Ty, Quals.getAsOpaqueValue()); - return Context.getUnaryTransformType(BaseType, Underlying, - UnaryTransformType::AddVolatile); + 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 --- a/clang/test/SemaCXX/add_cv.cpp +++ b/clang/test/SemaCXX/add_cv.cpp @@ -7,6 +7,7 @@ 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; }