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 @@ -797,6 +797,9 @@ return Value.getPointer().isNull(); } + // Determines if a type can form `T&`. + 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. @@ -4637,7 +4640,8 @@ class UnaryTransformType : public Type { public: enum UTTKind { - EnumUnderlyingType +#define TRANSFORM_TYPE_TRAIT_DEF(Enum, _) Enum, +#include "clang/Basic/TransformTypeTraits.def" }; private: @@ -6584,6 +6588,19 @@ 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 (const auto *F = Self.getAs()) + return F->getMethodQuals().empty() && F->getRefQualifier() == RQ_None; + + return false; +} + inline SplitQualType QualType::split() const { if (!hasLocalNonFastQualifiers()) return SplitQualType(getTypePtrUnsafe(), diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -8674,6 +8674,10 @@ "a vector of such types is required">; def err_cast_selector_expr : Error< "cannot type cast @selector expression">; +def err_make_signed_integral_only : Error< + "'%select{make_unsigned|make_signed}0' is only compatible with " + "non-%select{bool|_BitInt(1)}1 integers and enum types, but was given " + "%2%select{| whose underlying type is %4}3">; def ext_typecheck_cond_incompatible_pointers : ExtWarn< "pointer type mismatch%diff{ ($ and $)|}0,1">, InGroup>; 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,42 @@ 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 +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) TST_##Trait, +#include "clang/Basic/TransformTypeTraits.def" + 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 @@ -96,8 +97,8 @@ /// Structure that packs information about the type specifiers that /// were written in a particular type specifier sequence. struct WrittenBuiltinSpecs { - static_assert(TST_error < 1 << 6, "Type bitfield not wide enough for TST"); - /*DeclSpec::TST*/ unsigned Type : 6; + static_assert(TST_error < 1 << 7, "Type bitfield not wide enough for TST"); + /*DeclSpec::TST*/ unsigned Type : 7; /*DeclSpec::TSS*/ unsigned Sign : 2; /*TypeSpecifierWidth*/ unsigned Width : 2; unsigned ModeAttr : 1; 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 @@ -501,7 +501,9 @@ TYPE_TRAIT_1(__is_union, IsUnion, KEYCXX) TYPE_TRAIT_1(__has_unique_object_representations, HasUniqueObjectRepresentations, KEYCXX) -KEYWORD(__underlying_type , KEYCXX) + +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) KEYWORD(__##Trait, KEYCXX) +#include "clang/Basic/TransformTypeTraits.def" // Clang-only C++ Type Traits TYPE_TRAIT_1(__is_trivially_relocatable, IsTriviallyRelocatable, KEYCXX) diff --git a/clang/include/clang/Basic/TransformTypeTraits.def b/clang/include/clang/Basic/TransformTypeTraits.def new file mode 100644 --- /dev/null +++ b/clang/include/clang/Basic/TransformTypeTraits.def @@ -0,0 +1,29 @@ +//==--- TransformTypeTraits.def - type trait transformations --------------===// +// +// 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 file defines transform type traits' names. +// +//===----------------------------------------------------------------------===// + +TRANSFORM_TYPE_TRAIT_DEF(AddLvalueReference, add_lvalue_reference) +TRANSFORM_TYPE_TRAIT_DEF(AddPointer, add_pointer) +TRANSFORM_TYPE_TRAIT_DEF(AddRvalueReference, add_rvalue_reference) +TRANSFORM_TYPE_TRAIT_DEF(Decay, decay) +TRANSFORM_TYPE_TRAIT_DEF(MakeSigned, make_signed) +TRANSFORM_TYPE_TRAIT_DEF(MakeUnsigned, make_unsigned) +TRANSFORM_TYPE_TRAIT_DEF(RemoveAllExtents, remove_all_extents) +TRANSFORM_TYPE_TRAIT_DEF(RemoveConst, remove_const) +TRANSFORM_TYPE_TRAIT_DEF(RemoveCV, remove_cv) +TRANSFORM_TYPE_TRAIT_DEF(RemoveCVRef, remove_cvref) +TRANSFORM_TYPE_TRAIT_DEF(RemoveExtent, remove_extent) +TRANSFORM_TYPE_TRAIT_DEF(RemovePointer, remove_pointer) +TRANSFORM_TYPE_TRAIT_DEF(RemoveReference, remove_reference) +TRANSFORM_TYPE_TRAIT_DEF(RemoveRestrict, remove_restrict) +TRANSFORM_TYPE_TRAIT_DEF(RemoveVolatile, remove_volatile) +TRANSFORM_TYPE_TRAIT_DEF(EnumUnderlyingType, underlying_type) +#undef TRANSFORM_TYPE_TRAIT_DEF 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 @@ -2906,7 +2906,6 @@ void AnnotateExistingDecltypeSpecifier(const DeclSpec &DS, SourceLocation StartLoc, SourceLocation EndLoc); - void ParseUnderlyingTypeSpecifier(DeclSpec &DS); void ParseAtomicSpecifier(DeclSpec &DS); ExprResult ParseAlignArgument(SourceLocation Start, @@ -3004,6 +3003,8 @@ SourceLocation &EllipsisLoc); void ParseBracketDeclarator(Declarator &D); void ParseMisplacedBracketDeclarator(Declarator &D); + bool MaybeParseTypeTransformTypeSpecifier(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 @@ -32,6 +32,7 @@ #include "clang/Lex/Token.h" #include "clang/Sema/Ownership.h" #include "clang/Sema/ParsedAttr.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" @@ -290,7 +291,9 @@ static const TST TST_typeofExpr = clang::TST_typeofExpr; 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; +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) \ + static const TST TST_##Trait = clang::TST_##Trait; +#include "clang/Basic/TransformTypeTraits.def" 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; @@ -333,7 +336,7 @@ /*TypeSpecifierWidth*/ unsigned TypeSpecWidth : 2; /*TSC*/unsigned TypeSpecComplex : 2; /*TSS*/unsigned TypeSpecSign : 2; - /*TST*/unsigned TypeSpecType : 6; + /*TST*/unsigned TypeSpecType : 7; unsigned TypeAltiVecVector : 1; unsigned TypeAltiVecPixel : 1; unsigned TypeAltiVecBool : 1; @@ -400,8 +403,8 @@ ObjCDeclSpec *ObjCQualifiers; static bool isTypeRep(TST T) { - return (T == TST_typename || T == TST_typeofType || - T == TST_underlyingType || T == TST_atomic); + return T == TST_atomic || T == TST_typename || T == TST_typeofType || + isTransformTypeTrait(T); } static bool isExprRep(TST T) { return (T == TST_typeofExpr || T == TST_decltype || T == TST_bitint); @@ -418,6 +421,14 @@ T == TST_interface || T == TST_union || T == TST_class); } + static bool isTransformTypeTrait(TST T) { + constexpr std::array Traits = { +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) TST_##Trait, +#include "clang/Basic/TransformTypeTraits.def" + }; + + return T >= Traits.front() && T <= Traits.back(); + } DeclSpec(AttributeFactory &attrFactory) : StorageClassSpec(SCS_unspecified), @@ -522,7 +533,7 @@ } SourceRange getTypeofParensRange() const { return TypeofParensRange; } - void setTypeofParensRange(SourceRange range) { TypeofParensRange = range; } + void setTypeArgumentRange(SourceRange range) { TypeofParensRange = range; } bool hasAutoTypeSpec() const { return (TypeSpecType == TST_auto || TypeSpecType == TST_auto_type || diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2511,8 +2511,23 @@ /// If AsUnevaluated is false, E is treated as though it were an evaluated /// context, such as when building a type for decltype(auto). QualType BuildDecltypeType(Expr *E, bool AsUnevaluated = true); - QualType BuildUnaryTransformType(QualType BaseType, - UnaryTransformType::UTTKind UKind, + + using UTTKind = UnaryTransformType::UTTKind; + QualType BuildUnaryTransformType(QualType BaseType, UTTKind UKind, + SourceLocation Loc); + QualType BuiltinEnumUnderlyingType(QualType BaseType, SourceLocation Loc); + QualType BuiltinAddPointer(QualType BaseType, SourceLocation Loc); + QualType BuiltinRemovePointer(QualType BaseType, SourceLocation Loc); + QualType BuiltinDecay(QualType BaseType, SourceLocation Loc); + QualType BuiltinAddReference(QualType BaseType, UTTKind UKind, + SourceLocation Loc); + QualType BuiltinRemoveExtent(QualType BaseType, UTTKind UKind, + SourceLocation Loc); + QualType BuiltinRemoveReference(QualType BaseType, UTTKind UKind, + SourceLocation Loc); + QualType BuiltinChangeCVRQualifiers(QualType BaseType, UTTKind UKind, + SourceLocation Loc); + QualType BuiltinChangeSignedness(QualType BaseType, UTTKind UKind, SourceLocation Loc); //===--------------------------------------------------------------------===// diff --git a/clang/include/clang/module.modulemap b/clang/include/clang/module.modulemap --- a/clang/include/clang/module.modulemap +++ b/clang/include/clang/module.modulemap @@ -71,6 +71,7 @@ textual header "Basic/RISCVVTypes.def" textual header "Basic/Sanitizers.def" textual header "Basic/TargetCXXABI.def" + textual header "Basic/TransformTypeTraits.def" module * { export * } } diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -10781,7 +10781,8 @@ } QualType ASTContext::getCorrespondingUnsignedType(QualType T) const { - assert((T->hasSignedIntegerRepresentation() || T->isSignedFixedPointType()) && + assert((T->hasIntegerRepresentation() || T->isEnumeralType() || + T->isFixedPointType()) && "Unexpected type"); // Turn <4 x signed int> -> <4 x unsigned int> @@ -10799,8 +10800,11 @@ T = ETy->getDecl()->getIntegerType(); switch (T->castAs()->getKind()) { + case BuiltinType::Char_U: + // Plain `char` is mapped to `unsigned char` even if it's already unsigned case BuiltinType::Char_S: case BuiltinType::SChar: + case BuiltinType::Char8: return UnsignedCharTy; case BuiltinType::Short: return UnsignedShortTy; @@ -10814,7 +10818,7 @@ return UnsignedInt128Ty; // wchar_t is special. It is either signed or not, but when it's signed, // there's no matching "unsigned wchar_t". Therefore we return the unsigned - // version of it's underlying type instead. + // version of its underlying type instead. case BuiltinType::WChar_S: return getUnsignedWCharType(); @@ -10843,13 +10847,16 @@ case BuiltinType::SatLongFract: return SatUnsignedLongFractTy; default: - llvm_unreachable("Unexpected signed integer or fixed point type"); + assert((T->hasUnsignedIntegerRepresentation() || + T->isUnsignedFixedPointType()) && + "Unexpected signed integer or fixed point type"); + return T; } } QualType ASTContext::getCorrespondingSignedType(QualType T) const { - assert((T->hasUnsignedIntegerRepresentation() || - T->isUnsignedFixedPointType()) && + assert((T->hasIntegerRepresentation() || T->isEnumeralType() || + T->isFixedPointType()) && "Unexpected type"); // Turn <4 x unsigned int> -> <4 x signed int> @@ -10867,8 +10874,11 @@ T = ETy->getDecl()->getIntegerType(); switch (T->castAs()->getKind()) { + case BuiltinType::Char_S: + // Plain `char` is mapped to `signed char` even if it's already signed case BuiltinType::Char_U: case BuiltinType::UChar: + case BuiltinType::Char8: return SignedCharTy; case BuiltinType::UShort: return ShortTy; @@ -10882,7 +10892,7 @@ return Int128Ty; // wchar_t is special. It is either unsigned or not, but when it's unsigned, // there's no matching "signed wchar_t". Therefore we return the signed - // version of it's underlying type instead. + // version of its underlying type instead. case BuiltinType::WChar_U: return getSignedWCharType(); @@ -10911,7 +10921,10 @@ case BuiltinType::SatULongFract: return SatLongFractTy; default: - llvm_unreachable("Unexpected unsigned integer or fixed point type"); + assert( + (T->hasSignedIntegerRepresentation() || T->isSignedFixedPointType()) && + "Unexpected signed integer or fixed point type"); + return T; } } 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 @@ -3980,16 +3980,22 @@ // If this is dependent, we need to record that. If not, we simply // mangle it as the underlying type since they are equivalent. if (T->isDependentType()) { - Out << 'U'; + Out << "u"; + StringRef BuiltinName; switch (T->getUTTKind()) { - case UnaryTransformType::EnumUnderlyingType: - Out << "3eut"; - break; +#define TRANSFORM_TYPE_TRAIT_DEF(Enum, Trait) \ + case UnaryTransformType::Enum: \ + BuiltinName = "__" #Trait; \ + break; +#include "clang/Basic/TransformTypeTraits.def" } + Out << BuiltinName.size() << BuiltinName; } + Out << "I"; mangleType(T->getBaseType()); + Out << "E"; } void CXXNameMangler::mangleType(const AutoType *T) { 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 @@ -1,4 +1,5 @@ #include "clang/AST/JSONNodeDumper.h" +#include "clang/AST/Type.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/Specifiers.h" #include "clang/Lex/Lexer.h" @@ -662,9 +663,11 @@ void JSONNodeDumper::VisitUnaryTransformType(const UnaryTransformType *UTT) { switch (UTT->getUTTKind()) { - case UnaryTransformType::EnumUnderlyingType: - JOS.attribute("transformKind", "underlying_type"); +#define TRANSFORM_TYPE_TRAIT_DEF(Enum, Trait) \ + case UnaryTransformType::Enum: \ + JOS.attribute("transformKind", #Trait); \ break; +#include "clang/Basic/TransformTypeTraits.def" } } 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 @@ -1551,9 +1551,11 @@ void TextNodeDumper::VisitUnaryTransformType(const UnaryTransformType *T) { switch (T->getUTTKind()) { - case UnaryTransformType::EnumUnderlyingType: - OS << " underlying_type"; +#define TRANSFORM_TYPE_TRAIT_DEF(Enum, Trait) \ + case UnaryTransformType::Enum: \ + OS << " " #Trait; \ break; +#include "clang/Basic/TransformTypeTraits.def" } } 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" @@ -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" @@ -1140,29 +1142,19 @@ raw_ostream &OS) { IncludeStrongLifetimeRAII Strong(Policy); - switch (T->getUTTKind()) { - case UnaryTransformType::EnumUnderlyingType: - OS << "__underlying_type("; - print(T->getBaseType(), OS, StringRef()); - OS << ')'; - spaceBeforePlaceHolder(OS); - return; - } - - printBefore(T->getBaseType(), OS); + static llvm::DenseMap Transformation = {{ +#define TRANSFORM_TYPE_TRAIT_DEF(Enum, Trait) \ + {UnaryTransformType::Enum, "__" #Trait}, +#include "clang/Basic/TransformTypeTraits.def" + }}; + OS << Transformation[T->getUTTKind()] << '('; + print(T->getBaseType(), OS, StringRef()); + OS << ')'; + spaceBeforePlaceHolder(OS); } void TypePrinter::printUnaryTransformAfter(const UnaryTransformType *T, - raw_ostream &OS) { - IncludeStrongLifetimeRAII Strong(Policy); - - switch (T->getUTTKind()) { - case UnaryTransformType::EnumUnderlyingType: - return; - } - - printAfter(T->getBaseType(), OS); -} + raw_ostream &OS) {} void TypePrinter::printAutoBefore(const AutoType *T, raw_ostream &OS) { // If the type has been deduced, do not print 'auto'. diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -681,7 +681,8 @@ case tok::kw_static_assert: case tok::kw__Atomic: case tok::kw___attribute: - case tok::kw___underlying_type: +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait: +#include "clang/Basic/TransformTypeTraits.def" case tok::kw_requires: return true; default: 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 @@ -56,7 +56,8 @@ case tok::kw___ibm128: case tok::kw_wchar_t: case tok::kw_bool: - case tok::kw___underlying_type: +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait: +#include "clang/Basic/TransformTypeTraits.def" case tok::annot_typename: case tok::kw_char8_t: case tok::kw_char16_t: diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -317,8 +317,10 @@ if (PrevNonComment->is(tok::kw___attribute)) { OpeningParen.setType(TT_AttributeParen); } else if (PrevNonComment->isOneOf(TT_TypenameMacro, tok::kw_decltype, - tok::kw_typeof, tok::kw__Atomic, - tok::kw___underlying_type)) { + tok::kw_typeof, +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) tok::kw___##Trait, +#include "clang/Basic/TransformTypeTraits.def" + tok::kw__Atomic)) { OpeningParen.setType(TT_TypeDeclarationParen); // decltype() and typeof() usually contain expressions. if (PrevNonComment->isOneOf(tok::kw_decltype, tok::kw_typeof)) 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 @@ -1663,7 +1663,8 @@ .Case("__array_rank", true) .Case("__array_extent", true) .Case("__reference_binds_to_temporary", true) - .Case("__underlying_type", true) +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) .Case("__" #Trait, true) +#include "clang/Basic/TransformTypeTraits.def" .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 @@ -3472,7 +3472,8 @@ // typedef-name case tok::kw___super: case tok::kw_decltype: - case tok::identifier: { + case tok::identifier: + ParseIdentifier: { // This identifier can only be a typedef name if we haven't already seen // a type-specifier. Without this check we misparse: // typedef int X; struct Y { short X; }; as 'short int'. @@ -3665,7 +3666,7 @@ } } ConsumedEnd = Tok.getLocation(); - DS.setTypeofParensRange(Tracker.getRange()); + DS.setTypeArgumentRange(Tracker.getRange()); // Even if something went wrong above, continue as if we've seen // `decltype(auto)`. isInvalid = DS.SetTypeSpecType(TST_decltype_auto, Loc, PrevSpec, @@ -4207,8 +4208,13 @@ HandlePragmaMSPointersToMembers(); continue; - case tok::kw___underlying_type: - ParseUnderlyingTypeSpecifier(DS); +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait: +#include "clang/Basic/TransformTypeTraits.def" + // HACK: libstdc++ already uses '__remove_cv' as an alias template so we + // work around this by expecting all transform type traits to be suffixed + // with '('. They're an identifier otherwise. + if (!MaybeParseTypeTransformTypeSpecifier(DS)) + goto ParseIdentifier; continue; case tok::kw__Atomic: @@ -7446,7 +7452,7 @@ ExprResult Operand = Actions.CorrectDelayedTyposInExpr( ParseExprAfterUnaryExprOrTypeTrait(OpTok, isCastExpr, CastTy, CastRange)); if (hasParens) - DS.setTypeofParensRange(CastRange); + DS.setTypeArgumentRange(CastRange); if (CastRange.getEnd().isInvalid()) // FIXME: Not accurate, the range gets one token more than it should. @@ -7516,7 +7522,7 @@ if (T.getCloseLocation().isInvalid()) return; - DS.setTypeofParensRange(T.getRange()); + DS.setTypeArgumentRange(T.getRange()); DS.SetRangeEnd(T.getCloseLocation()); const char *PrevSpec = nullptr; 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 @@ -18,6 +18,7 @@ #include "clang/Basic/CharInfo.h" #include "clang/Basic/OperatorKinds.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TokenKinds.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" #include "clang/Parse/RAIIObjectsForParser.h" @@ -1021,7 +1022,7 @@ EndLoc = Tok.getAnnotationEndLoc(); // Unfortunately, we don't know the LParen source location as the annotated // token doesn't have it. - DS.setTypeofParensRange(SourceRange(SourceLocation(), EndLoc)); + DS.setTypeArgumentRange(SourceRange(SourceLocation(), EndLoc)); ConsumeAnnotationToken(); if (Result.isInvalid()) { DS.SetTypeSpecError(); @@ -1085,7 +1086,7 @@ // Match the ')' T.consumeClose(); - DS.setTypeofParensRange(T.getRange()); + DS.setTypeArgumentRange(T.getRange()); if (T.getCloseLocation().isInvalid()) { DS.SetTypeSpecError(); // FIXME: this should return the location of the last token @@ -1142,35 +1143,48 @@ PP.AnnotateCachedTokens(Tok); } -void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) { - assert(Tok.is(tok::kw___underlying_type) && - "Not an underlying type specifier"); +DeclSpec::TST Parser::TypeTransformTokToDeclSpec() { + switch (Tok.getKind()) { +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) \ + case tok::kw___##Trait: \ + return DeclSpec::TST_##Trait; +#include "clang/Basic/TransformTypeTraits.def" + default: + llvm_unreachable("passed in an unhandled type transformation built-in"); + } +} +bool Parser::MaybeParseTypeTransformTypeSpecifier(DeclSpec &DS) { + if (!NextToken().is(tok::l_paren)) { + Tok.setKind(tok::identifier); + return false; + } + DeclSpec::TST TypeTransformTST = TypeTransformTokToDeclSpec(); SourceLocation StartLoc = ConsumeToken(); + BalancedDelimiterTracker T(*this, tok::l_paren); - if (T.expectAndConsume(diag::err_expected_lparen_after, "__underlying_type", - tok::r_paren)) { - return; - } + if (T.expectAndConsume(diag::err_expected_lparen_after, Tok.getName(), + tok::r_paren)) + return true; TypeResult Result = ParseTypeName(); if (Result.isInvalid()) { SkipUntil(tok::r_paren, StopAtSemi); - return; + return true; } - // Match the ')' T.consumeClose(); if (T.getCloseLocation().isInvalid()) - return; + return true; const char *PrevSpec = nullptr; unsigned DiagID; - if (DS.SetTypeSpecType(DeclSpec::TST_underlyingType, StartLoc, PrevSpec, - DiagID, Result.get(), + if (DS.SetTypeSpecType(TypeTransformTST, StartLoc, PrevSpec, DiagID, + Result.get(), Actions.getASTContext().getPrintingPolicy())) Diag(StartLoc, DiagID) << PrevSpec; - DS.setTypeofParensRange(T.getRange()); + DS.setTypeArgumentRange(T.getRange()); + return true; } /// ParseBaseTypeSpecifier - Parse a C++ base-type-specifier which is either a @@ -1525,28 +1539,58 @@ 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, +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) tok::kw___##Trait, +#include "clang/Basic/TransformTypeTraits.def" + 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_trivially_constructible, + tok::kw___is_trivially_copyable, + tok::kw___is_union, + tok::kw___is_unsigned, + tok::kw___is_void, tok::kw___is_volatile)) // GNU libstdc++ 4.2 and libc++ use certain intrinsic names as the // name of struct templates, but some are keywords in GCC >= 4.3 diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -1038,9 +1038,10 @@ return ParseCastExpression(ParseKind, isAddressOfOperand, isTypeCast, isVectorLiteral, NotPrimaryExpression); - case tok::identifier: { // primary-expression: identifier - // unqualified-id: identifier - // constant: enumeration-constant + case tok::identifier: + ParseIdentifier: { // primary-expression: identifier + // unqualified-id: identifier + // constant: enumeration-constant // Turn a potentially qualified name into a annot_typename or // annot_cxxscope if it would be valid. This handles things like x::y, etc. if (getLangOpts().CPlusPlus) { @@ -1113,6 +1114,9 @@ REVERTIBLE_TYPE_TRAIT(__is_unsigned); REVERTIBLE_TYPE_TRAIT(__is_void); REVERTIBLE_TYPE_TRAIT(__is_volatile); +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) \ + REVERTIBLE_TYPE_TRAIT(RTT_JOIN(__, Trait)); +#include "clang/Basic/TransformTypeTraits.def" #undef REVERTIBLE_TYPE_TRAIT #undef RTT_JOIN } @@ -1739,6 +1743,17 @@ PreferredType.get(Tok.getLocation())); return ExprError(); } +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait: +#include "clang/Basic/TransformTypeTraits.def" + // HACK: libstdc++ uses some of the transform-type-traits as alias + // templates, so we need to work around this. + if (!NextToken().is(tok::l_paren)) { + Tok.setKind(tok::identifier); + Diag(Tok, diag::ext_keyword_as_ident) + << Tok.getIdentifierInfo()->getName() << 0; + goto ParseIdentifier; + } + goto ExpectedExpression; case tok::l_square: if (getLangOpts().CPlusPlus11) { if (getLangOpts().ObjC) { @@ -1766,6 +1781,7 @@ } [[fallthrough]]; default: + ExpectedExpression: NotCastExpr = true; return ExprError(); } diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -14,6 +14,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/ExprCXX.h" #include "clang/Basic/PrettyStackTrace.h" +#include "clang/Basic/TokenKinds.h" #include "clang/Lex/LiteralSupport.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" @@ -21,6 +22,7 @@ #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" #include @@ -2819,6 +2821,7 @@ // identifier // template-id (when it hasn't already been annotated) if (Tok.is(tok::identifier)) { + ParseIdentifier: // Consume the identifier. IdentifierInfo *Id = Tok.getIdentifierInfo(); SourceLocation IdLoc = ConsumeToken(); @@ -3053,9 +3056,20 @@ return false; } - Diag(Tok, diag::err_expected_unqualified_id) - << getLangOpts().CPlusPlus; - return true; + switch (Tok.getKind()) { +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait: +#include "clang/Basic/TransformTypeTraits.def" + if (!NextToken().is(tok::l_paren)) { + Tok.setKind(tok::identifier); + Diag(Tok, diag::ext_keyword_as_ident) + << Tok.getIdentifierInfo()->getName() << 0; + goto ParseIdentifier; + } + LLVM_FALLTHROUGH; + default: + Diag(Tok, diag::err_expected_unqualified_id) << getLangOpts().CPlusPlus; + return true; + } } /// ParseCXXNewExpression - Parse a C++ new-expression. New is used to allocate diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -14,6 +14,7 @@ #include "clang/AST/PrettyDeclStackTrace.h" #include "clang/Basic/Attributes.h" #include "clang/Basic/PrettyStackTrace.h" +#include "clang/Basic/TokenKinds.h" #include "clang/Parse/LoopHint.h" #include "clang/Parse/Parser.h" #include "clang/Parse/RAIIObjectsForParser.h" @@ -188,7 +189,8 @@ Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Statement); return StmtError(); - case tok::identifier: { + case tok::identifier: + ParseIdentifier: { Token Next = NextToken(); if (Next.is(tok::colon)) { // C99 6.8.1: labeled-statement // Both C++11 and GNU attributes preceding the label appertain to the @@ -261,7 +263,19 @@ return StmtError(); } - return ParseExprStatement(StmtCtx); + switch (Tok.getKind()) { +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait: +#include "clang/Basic/TransformTypeTraits.def" + if (NextToken().is(tok::less)) { + Tok.setKind(tok::identifier); + Diag(Tok, diag::ext_keyword_as_ident) + << Tok.getIdentifierInfo()->getName() << 0; + goto ParseIdentifier; + } + LLVM_FALLTHROUGH; + default: + return ParseExprStatement(StmtCtx); + } } case tok::kw___attribute: { diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -161,7 +161,9 @@ [[fallthrough]]; case tok::kw_typeof: case tok::kw___attribute: - case tok::kw___underlying_type: { +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait: +#include "clang/Basic/TransformTypeTraits.def" + { ConsumeToken(); if (Tok.isNot(tok::l_paren)) return TPResult::Error; @@ -1682,8 +1684,8 @@ return TPResult::True; } - // C++0x type traits support - case tok::kw___underlying_type: +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait: +#include "clang/Basic/TransformTypeTraits.def" return TPResult::True; // C11 _Atomic @@ -1721,7 +1723,8 @@ case tok::annot_template_id: case tok::annot_typename: case tok::kw_typeof: - case tok::kw___underlying_type: +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait: +#include "clang/Basic/TransformTypeTraits.def" return true; // elaborated-type-specifier 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" @@ -389,7 +390,8 @@ return E->getType()->isFunctionType(); return false; - case TST_underlyingType: +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case TST_##Trait: +#include "clang/Basic/TransformTypeTraits.def" case TST_typename: case TST_typeofType: { QualType QT = DS.getRepAsType().get(); @@ -576,7 +578,10 @@ case DeclSpec::TST_auto_type: return "__auto_type"; case DeclSpec::TST_decltype: return "(decltype)"; case DeclSpec::TST_decltype_auto: return "decltype(auto)"; - case DeclSpec::TST_underlyingType: return "__underlying_type"; +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) \ + case DeclSpec::TST_##Trait: \ + return "__" #Trait; +#include "clang/Basic/TransformTypeTraits.def" 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,7 +145,8 @@ case tok::kw___ibm128: case tok::kw_wchar_t: case tok::kw_bool: - case tok::kw___underlying_type: +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait: +#include "clang/Basic/TransformTypeTraits.def" case tok::kw___auto_type: return true; @@ -5923,7 +5924,8 @@ switch (DS.getTypeSpecType()) { case DeclSpec::TST_typename: case DeclSpec::TST_typeofType: - case DeclSpec::TST_underlyingType: +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case DeclSpec::TST_##Trait: +#include "clang/Basic/TransformTypeTraits.def" 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 @@ -858,7 +858,8 @@ switch (DS.getTypeSpecType()) { case TST_typename: case TST_typeofType: - case TST_underlyingType: +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case TST_##Trait: +#include "clang/Basic/TransformTypeTraits.def" 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 @@ -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/SourceLocation.h" #include "clang/Basic/Specifiers.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" @@ -33,6 +35,7 @@ #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" #include "clang/Sema/TemplateInstCallback.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSwitch.h" @@ -1247,6 +1250,18 @@ return OpenCLAccessAttr::Keyword_read_only; } +static UnaryTransformType::UTTKind +TSTToUnaryTransformType(DeclSpec::TST SwitchTST) { + switch (SwitchTST) { +#define TRANSFORM_TYPE_TRAIT_DEF(Enum, Trait) \ + case TST_##Trait: \ + return UnaryTransformType::Enum; +#include "clang/Basic/TransformTypeTraits.def" + 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 @@ -1628,12 +1643,13 @@ } break; } - case DeclSpec::TST_underlyingType: +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case DeclSpec::TST_##Trait: +#include "clang/Basic/TransformTypeTraits.def" 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; declarator.setInvalidType(true); @@ -6067,8 +6083,7 @@ TL.setRParenLoc(DS.getTypeofParensRange().getEnd()); } void VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) { - // FIXME: This holds only because we only have one unary transform. - assert(DS.getTypeSpecType() == DeclSpec::TST_underlyingType); + assert(DS.isTransformTypeTrait(DS.getTypeSpecType())); TL.setKWLoc(DS.getTypeSpecTypeLoc()); TL.setParensRange(DS.getTypeofParensRange()); assert(DS.getRepAsType()); @@ -9205,39 +9220,259 @@ return Context.getDecltypeType(E, getDecltypeForExpr(E)); } -QualType Sema::BuildUnaryTransformType(QualType BaseType, - UnaryTransformType::UTTKind UKind, - SourceLocation Loc) { - switch (UKind) { - case UnaryTransformType::EnumUnderlyingType: - if (!BaseType->isDependentType() && !BaseType->isEnumeralType()) { - Diag(Loc, diag::err_only_enums_have_underlying_types); - return QualType(); - } else { - QualType Underlying = BaseType; - if (!BaseType->isDependentType()) { - // The enum could be incomplete if we're parsing its definition or - // recovering from an error. - NamedDecl *FwdDecl = nullptr; - if (BaseType->isIncompleteType(&FwdDecl)) { - Diag(Loc, diag::err_underlying_type_of_incomplete_enum) << BaseType; - Diag(FwdDecl->getLocation(), diag::note_forward_declaration) << FwdDecl; - return QualType(); - } +static QualType GetEnumUnderlyingType(Sema &S, QualType BaseType, + SourceLocation Loc) { + assert(BaseType->isEnumeralType()); + EnumDecl *ED = BaseType->castAs()->getDecl(); + assert(ED && "EnumType has no EnumDecl"); - EnumDecl *ED = BaseType->castAs()->getDecl(); - assert(ED && "EnumType has no EnumDecl"); + S.DiagnoseUseOfDecl(ED, Loc); - DiagnoseUseOfDecl(ED, Loc); + QualType Underlying = ED->getIntegerType(); + assert(!Underlying.isNull()); - Underlying = ED->getIntegerType(); - assert(!Underlying.isNull()); - } - return Context.getUnaryTransformType(BaseType, Underlying, - UnaryTransformType::EnumUnderlyingType); + return Underlying; +} + +QualType Sema::BuiltinEnumUnderlyingType(QualType BaseType, + SourceLocation Loc) { + if (!BaseType->isEnumeralType()) { + Diag(Loc, diag::err_only_enums_have_underlying_types); + return QualType(); + } + + // The enum could be incomplete if we're parsing its definition or + // recovering from an error. + NamedDecl *FwdDecl = nullptr; + if (BaseType->isIncompleteType(&FwdDecl)) { + Diag(Loc, diag::err_underlying_type_of_incomplete_enum) << BaseType; + Diag(FwdDecl->getLocation(), diag::note_forward_declaration) << FwdDecl; + return QualType(); + } + + return GetEnumUnderlyingType(*this, BaseType, Loc); +} + +QualType Sema::BuiltinAddPointer(QualType BaseType, SourceLocation Loc) { + QualType Pointer = BaseType.isReferenceable() || BaseType->isVoidType() + ? BuildPointerType(BaseType.getNonReferenceType(), Loc, + DeclarationName()) + : BaseType; + + return Pointer.isNull() ? QualType() : Pointer; +} + +QualType Sema::BuiltinRemovePointer(QualType BaseType, SourceLocation Loc) { + // We don't want block pointers or ObjectiveC's id type. + if (!BaseType->isAnyPointerType() || BaseType->isObjCIdType()) + return BaseType; + + return BaseType->getPointeeType(); +} + +QualType Sema::BuiltinDecay(QualType BaseType, SourceLocation Loc) { + QualType Underlying = BaseType.getNonReferenceType(); + if (Underlying->isArrayType()) + return Context.getDecayedType(Underlying); + + if (Underlying->isFunctionType()) + return BuiltinAddPointer(BaseType, Loc); + + SplitQualType Split = Underlying.getSplitUnqualifiedType(); + // std::decay is supposed to produce 'std::remove_cv', but since 'restrict' is + // in the same group of qualifiers as 'const' and 'volatile', we're extending + // '__decay(T)' so that it removes all qualifiers. + Split.Quals.removeCVRQualifiers(); + return Context.getQualifiedType(Split); +} + +QualType Sema::BuiltinAddReference(QualType BaseType, UTTKind UKind, + SourceLocation Loc) { + assert(LangOpts.CPlusPlus); + QualType Reference = + BaseType.isReferenceable() + ? BuildReferenceType(BaseType, + UKind == UnaryTransformType::AddLvalueReference, + Loc, DeclarationName()) + : BaseType; + return Reference.isNull() ? QualType() : Reference; +} + +QualType Sema::BuiltinRemoveExtent(QualType BaseType, UTTKind UKind, + SourceLocation Loc) { + if (UKind == UnaryTransformType::RemoveAllExtents) + return Context.getBaseElementType(BaseType); + + if (const auto *AT = Context.getAsArrayType(BaseType)) + return AT->getElementType(); + + return BaseType; +} + +QualType Sema::BuiltinRemoveReference(QualType BaseType, UTTKind UKind, + SourceLocation Loc) { + assert(LangOpts.CPlusPlus); + QualType T = BaseType.getNonReferenceType(); + if (UKind == UTTKind::RemoveCVRef && + (T.isConstQualified() || T.isVolatileQualified())) { + Qualifiers Quals; + QualType Unqual = Context.getUnqualifiedArrayType(T, Quals); + Quals.removeConst(); + Quals.removeVolatile(); + T = Context.getQualifiedType(Unqual, Quals); + } + return T; +} + +QualType Sema::BuiltinChangeCVRQualifiers(QualType BaseType, UTTKind UKind, + SourceLocation Loc) { + if ((BaseType->isReferenceType() && UKind != UTTKind::RemoveRestrict) || + BaseType->isFunctionType()) + return BaseType; + + Qualifiers Quals; + QualType Unqual = Context.getUnqualifiedArrayType(BaseType, Quals); + + if (UKind == UTTKind::RemoveConst || UKind == UTTKind::RemoveCV) + Quals.removeConst(); + if (UKind == UTTKind::RemoveVolatile || UKind == UTTKind::RemoveCV) + Quals.removeVolatile(); + if (UKind == UTTKind::RemoveRestrict) + Quals.removeRestrict(); + + return Context.getQualifiedType(Unqual, Quals); +} + +static QualType ChangeIntegralSignedness(Sema &S, QualType BaseType, + bool IsMakeSigned, + SourceLocation Loc) { + if (BaseType->isEnumeralType()) { + QualType Underlying = GetEnumUnderlyingType(S, BaseType, Loc); + if (auto *BitInt = dyn_cast(Underlying)) { + unsigned int Bits = BitInt->getNumBits(); + if (Bits > 1) + return S.Context.getBitIntType(!IsMakeSigned, Bits); + + S.Diag(Loc, diag::err_make_signed_integral_only) + << IsMakeSigned << /*_BitInt(1)*/ true << BaseType << 1 << Underlying; + return QualType(); } + if (Underlying->isBooleanType()) { + S.Diag(Loc, diag::err_make_signed_integral_only) + << IsMakeSigned << /*_BitInt(1)*/ false << BaseType << 1 + << Underlying; + return QualType(); + } + } + + bool Int128Unsupported = !S.Context.getTargetInfo().hasInt128Type(); + std::array AllSignedIntegers = { + &S.Context.SignedCharTy, &S.Context.ShortTy, &S.Context.IntTy, + &S.Context.LongTy, &S.Context.LongLongTy, &S.Context.Int128Ty}; + ArrayRef AvailableSignedIntegers( + AllSignedIntegers.data(), AllSignedIntegers.size() - Int128Unsupported); + std::array AllUnsignedIntegers = { + &S.Context.UnsignedCharTy, &S.Context.UnsignedShortTy, + &S.Context.UnsignedIntTy, &S.Context.UnsignedLongTy, + &S.Context.UnsignedLongLongTy, &S.Context.UnsignedInt128Ty}; + ArrayRef AvailableUnsignedIntegers(AllUnsignedIntegers.data(), + AllUnsignedIntegers.size() - + Int128Unsupported); + ArrayRef *Consider = + IsMakeSigned ? &AvailableSignedIntegers : &AvailableUnsignedIntegers; + + uint64_t BaseSize = S.Context.getTypeSize(BaseType); + auto *Result = + llvm::find_if(*Consider, [&S, BaseSize](const CanQual *T) { + return BaseSize == S.Context.getTypeSize(T->getTypePtr()); + }); + + assert(Result != Consider->end()); + return QualType((*Result)->getTypePtr(), 0); +} + +QualType Sema::BuiltinChangeSignedness(QualType BaseType, UTTKind UKind, + SourceLocation Loc) { + bool IsMakeSigned = UKind == UnaryTransformType::MakeSigned; + if ((!BaseType->isIntegerType() && !BaseType->isEnumeralType()) || + BaseType->isBooleanType() || + (BaseType->isBitIntType() && + BaseType->getAs()->getNumBits() < 2)) { + Diag(Loc, diag::err_make_signed_integral_only) + << IsMakeSigned << BaseType->isBitIntType() << BaseType << 0; + return QualType(); + } + + bool IsNonIntIntegral = + BaseType->isChar16Type() || BaseType->isChar32Type() || + BaseType->isWideCharType() || BaseType->isEnumeralType(); + + QualType Underlying = + IsNonIntIntegral + ? ChangeIntegralSignedness(*this, BaseType, IsMakeSigned, Loc) + : IsMakeSigned ? Context.getCorrespondingSignedType(BaseType) + : Context.getCorrespondingUnsignedType(BaseType); + if (Underlying.isNull()) + return Underlying; + return Context.getQualifiedType(Underlying, BaseType.getQualifiers()); +} + +QualType Sema::BuildUnaryTransformType(QualType BaseType, UTTKind UKind, + SourceLocation Loc) { + if (BaseType->isDependentType()) + return Context.getUnaryTransformType(BaseType, BaseType, UKind); + QualType Result; + switch (UKind) { + case UnaryTransformType::EnumUnderlyingType: { + Result = BuiltinEnumUnderlyingType(BaseType, Loc); + break; + } + case UnaryTransformType::AddPointer: { + Result = BuiltinAddPointer(BaseType, Loc); + break; + } + case UnaryTransformType::RemovePointer: { + Result = BuiltinRemovePointer(BaseType, Loc); + break; + } + case UnaryTransformType::Decay: { + Result = BuiltinDecay(BaseType, Loc); + break; + } + case UnaryTransformType::AddLvalueReference: + case UnaryTransformType::AddRvalueReference: { + Result = BuiltinAddReference(BaseType, UKind, Loc); + break; } - llvm_unreachable("unknown unary transform type"); + case UnaryTransformType::RemoveAllExtents: + case UnaryTransformType::RemoveExtent: { + Result = BuiltinRemoveExtent(BaseType, UKind, Loc); + break; + } + case UnaryTransformType::RemoveCVRef: + case UnaryTransformType::RemoveReference: { + Result = BuiltinRemoveReference(BaseType, UKind, Loc); + break; + } + case UnaryTransformType::RemoveConst: + case UnaryTransformType::RemoveCV: + case UnaryTransformType::RemoveRestrict: + case UnaryTransformType::RemoveVolatile: { + Result = BuiltinChangeCVRQualifiers(BaseType, UKind, Loc); + break; + } + case UnaryTransformType::MakeSigned: + case UnaryTransformType::MakeUnsigned: { + Result = BuiltinChangeSignedness(BaseType, UKind, Loc); + break; + } + default: + llvm_unreachable("unknown unary transform type"); + } + + return !Result.isNull() + ? Context.getUnaryTransformType(BaseType, Result, UKind) + : Result; } QualType Sema::BuildAtomicType(QualType T, SourceLocation Loc) { diff --git a/clang/test/CodeGenCXX/mangle.cpp b/clang/test/CodeGenCXX/mangle.cpp --- a/clang/test/CodeGenCXX/mangle.cpp +++ b/clang/test/CodeGenCXX/mangle.cpp @@ -51,7 +51,7 @@ namespace N { int h(); void g() { static int a = h(); } } // CHECK-LABEL: define{{.*}} void @_Z1fno -void f(__int128_t, __uint128_t) { } +void f(__int128_t, __uint128_t) {} template struct S1 {}; @@ -101,13 +101,13 @@ void g1() { // CHECK: @_Z3ft1IidEvT0_T_ ft1(1, 0); - + // CHECK: @_Z3ft2IcEvT_PFvS0_ES2_ ft2(1, 0, 0); - + // CHECK: @_Z3ft3IiEvP2S4IT_2S1IS1_EE ft3(0); - + // CHECK: @_ZN2NS3ft1IiEEvT_ NS::ft1(1); } @@ -119,14 +119,14 @@ void g2() { // CHECK: @_Z3ft4ILi10EEv2S5IXT_EE ft4(S5<10>()); - + // CHECK: @_Z3ft4ILi20EEv2S5IXT_EE ft4(S5<20>()); } extern "C++" { // CHECK: @_Z1hv - void h() { } +void h() {} } // PR5019 @@ -208,7 +208,7 @@ struct S7 { S7(); - + struct S { S(); }; struct { S s; @@ -276,7 +276,7 @@ Ops& operator-(const Ops&); Ops& operator&(const Ops&); Ops& operator*(const Ops&); - + void *v; }; @@ -493,7 +493,7 @@ struct A { void f(...); }; - + // CHECK: @_ZN6test111A1fEz void A::f(...) { } } @@ -832,9 +832,9 @@ namespace test35 { // Dependent operator names of unknown arity. - struct A { - template A operator+(U) const; - }; +struct A { + template A operator+(U) const; +}; template void f1(decltype(sizeof(&T::template operator+))) {} @@ -1107,11 +1107,74 @@ enum E { R }; template -void fn(T, __underlying_type(T)) {} - -template void fn(E, __underlying_type(E)); -// CHECK-LABEL: @_ZN6test552fnINS_1EEEEvT_U3eutS2_ -} +void f1(T, __underlying_type(T)) {} +template void f1(E, __underlying_type(E)); +// CHECK-LABEL: @_ZN6test552f1INS_1EEEEvT_u17__underlying_typeIS2_E + +template void f2(T, __add_lvalue_reference(T)) {} +template void f2(int, __add_lvalue_reference(int)); +// CHECK-LABEL: @_ZN6test552f2IiEEvT_u22__add_lvalue_referenceIS1_E + +template void f3(T, __add_pointer(T)) {} +template void f3(int, __add_pointer(int)); +// CHECK-LABEL: @_ZN6test552f3IiEEvT_u13__add_pointerIS1_E + +template void f4(T, __add_rvalue_reference(T)) {} +template void f4(int, __add_rvalue_reference(int)); +// CHECK-LABEL: @_ZN6test552f4IiEEvT_u22__add_rvalue_referenceIS1_E + +template void f5(T, __decay(T)) {} +template void f5(int, __decay(int)); +// CHECK-LABEL: @_ZN6test552f5IiEEvT_u7__decayIS1_E + +template void f6(T, __make_signed(T)) {} +template void f6(int, __make_signed(int)); +// CHECK-LABEL: @_ZN6test552f6IiEEvT_u13__make_signedIS1_E + +template void f7(T, __make_unsigned(T)) {} +template void f7(int, __make_unsigned(int)); +// CHECK-LABEL: @_ZN6test552f7IiEEvT_u15__make_unsignedIS1_E + +template void f8(T, __remove_const(T)) {} +template void f8(int, __remove_const(int)); +// CHECK-LABEL: @_ZN6test552f8IiEEvT_u14__remove_constIS1_E + +template void f9(T, __remove_cv(T)) {} +template void f9(int, __remove_cv(int)); +// CHECK-LABEL: @_ZN6test552f9IiEEvT_u11__remove_cvIS1_E + +template void f10(T, __remove_cvref(T)) {} +template void f10(int, __remove_cvref(int)); +// CHECK-LABEL: @_ZN6test553f10IiEEvT_u14__remove_cvrefIS1_E + +template void f11(T, __remove_volatile(T)) {} +template void f11(int, __remove_volatile(int)); +// CHECK-LABEL: @_ZN6test553f11IiEEvT_u17__remove_volatileIS1_E + +template void f12(T, __remove_extent(T)) {} +template void f12(int, __remove_extent(int)); +// CHECK-LABEL: @_ZN6test553f12IiEEvT_u15__remove_extentIS1_E + +template void f13(T, __remove_all_extents(T)) {} +template void f13(int, __remove_all_extents(int)); +// CHECK-LABEL: @_ZN6test553f13IiEEvT_u20__remove_all_extentsIS1_E + +template void f14(T, __remove_pointer(T)) {} +template void f14(int, __remove_pointer(int)); +// CHECK-LABEL: @_ZN6test553f14IiEEvT_u16__remove_pointerIS1_E + +template void f15(T, __remove_reference(T)) {} +template void f15(int, __remove_reference(int)); +// CHECK-LABEL: @_ZN6test553f15IiEEvT_u18__remove_referenceIS1_E + +template void f16(T, __remove_volatile(T)) {} +template void f16(int, __remove_volatile(int)); +// CHECK-LABEL: @_ZN6test553f16IiEEvT_u17__remove_volatileIS1_E + +template void f17(T, __remove_restrict(T)) {} +template void f17(int, __remove_restrict(int)); +// CHECK-LABEL: @_ZN6test553f17IiEEvT_u17__remove_restrictIS1_E +} // namespace test55 namespace test56 { struct A { A *operator->(); int n; } a; diff --git a/clang/test/SemaCXX/libstdcxx_transform_type_traits_hack.cpp b/clang/test/SemaCXX/libstdcxx_transform_type_traits_hack.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaCXX/libstdcxx_transform_type_traits_hack.cpp @@ -0,0 +1,84 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++11 -fms-extensions -Wno-microsoft %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++14 -fms-extensions -Wno-microsoft %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++1z -fms-extensions -Wno-microsoft %s + +// libstdc++ uses __remove_cv as an alias, so we make our transform type traits alias-revertible +template +struct Same { + static constexpr auto value = __is_same(T, U); +}; + +template +using __remove_const = int; // expected-warning{{keyword '__remove_const' will be made available as an identifier here}} +template +using A = Same<__remove_const, __remove_const>; + +template +using __remove_restrict = int; // expected-warning{{keyword '__remove_restrict' will be made available as an identifier here}} +template +using B = Same<__remove_restrict, __remove_restrict>; + +template +using __remove_volatile = int; // expected-warning{{keyword '__remove_volatile' will be made available as an identifier here}} +template +using C = Same<__remove_volatile, __remove_volatile>; + +template +using __remove_cv = int; // expected-warning{{keyword '__remove_cv' will be made available as an identifier here}} +template +using D = Same<__remove_cv, __remove_cv>; + +template +using __add_pointer = int; // expected-warning{{keyword '__add_pointer' will be made available as an identifier here}} +template +using E = Same<__add_pointer, __add_pointer>; + +template +using __remove_pointer = int; // expected-warning{{keyword '__remove_pointer' will be made available as an identifier here}} +template +using F = Same<__remove_pointer, __remove_pointer>; + +template +using __add_lvalue_reference = int; // expected-warning{{keyword '__add_lvalue_reference' will be made available as an identifier here}} +template +using G = Same<__add_lvalue_reference, __add_lvalue_reference>; + +template +using __add_rvalue_reference = int; // expected-warning{{keyword '__add_rvalue_reference' will be made available as an identifier here}} +template +using H = Same<__add_rvalue_reference, __add_rvalue_reference>; + +template +using __remove_reference = int; // expected-warning{{keyword '__remove_reference' will be made available as an identifier here}} +template +using I = Same<__remove_reference, __remove_reference>; + +template +using __remove_cvref = int; // expected-warning{{keyword '__remove_cvref' will be made available as an identifier here}} +template +using J = Same<__remove_cvref, __remove_cvref>; + +template +using __decay = int; // expected-warning{{keyword '__decay' will be made available as an identifier here}} +template +using K = Same<__decay, __decay>; + +template +using __make_signed = int; // expected-warning{{keyword '__make_signed' will be made available as an identifier here}} +template +using L = Same<__make_signed, __make_signed>; + +template +using __make_unsigned = int; // expected-warning{{keyword '__make_unsigned' will be made available as an identifier here}} +template +using M = Same<__make_unsigned, __make_unsigned>; + +template +using __remove_extent = int; // expected-warning{{keyword '__remove_extent' will be made available as an identifier here}} +template +using N = Same<__remove_extent, __remove_extent>; + +template +using __remove_all_extents = int; // expected-warning{{keyword '__remove_all_extents' will be made available as an identifier here}} +template +using O = Same<__remove_all_extents, __remove_all_extents>; diff --git a/clang/test/SemaCXX/remove_pointer.mm b/clang/test/SemaCXX/remove_pointer.mm new file mode 100644 --- /dev/null +++ b/clang/test/SemaCXX/remove_pointer.mm @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +// expected-no-diagnostics + +@class X; + +static_assert(__is_same(__remove_pointer(X *), X), ""); +static_assert(__is_same(__remove_pointer(id), id), ""); diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp --- a/clang/test/SemaCXX/type-traits.cpp +++ b/clang/test/SemaCXX/type-traits.cpp @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++11 -Wno-deprecated-builtins -fms-extensions -Wno-microsoft %s -// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++14 -Wno-deprecated-builtins -fms-extensions -Wno-microsoft %s -// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++1z -Wno-deprecated-builtins -fms-extensions -Wno-microsoft %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++11 -fblocks -Wno-deprecated-builtins -fms-extensions -Wno-microsoft %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++14 -fblocks -Wno-deprecated-builtins -fms-extensions -Wno-microsoft %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++1z -fblocks -Wno-deprecated-builtins -fms-extensions -Wno-microsoft %s #define T(b) (b) ? 1 : -1 #define F(b) (b) ? -1 : 1 @@ -14,6 +14,9 @@ enum Enum { EV }; enum SignedEnum : signed int { }; enum UnsignedEnum : unsigned int { }; +enum class EnumClass { EV }; +enum class SignedEnumClass : signed int {}; +enum class UnsignedEnumClass : unsigned int {}; struct POD { Enum e; int i; float f; NonPOD* p; }; struct Empty {}; struct IncompleteStruct; @@ -2915,3 +2918,694 @@ static_assert(__is_trivially_relocatable(TrivialAbiNontrivialMoveCtor[]), ""); } // namespace is_trivially_relocatable + +struct S {}; +template using remove_const_t = __remove_const(T); + +void check_remove_const() { + static_assert(__is_same(remove_const_t, void), ""); + static_assert(__is_same(remove_const_t, void), ""); + static_assert(__is_same(remove_const_t, int), ""); + static_assert(__is_same(remove_const_t, int), ""); + static_assert(__is_same(remove_const_t, volatile int), ""); + static_assert(__is_same(remove_const_t, volatile int), ""); + static_assert(__is_same(remove_const_t, int *), ""); + static_assert(__is_same(remove_const_t, int *), ""); + static_assert(__is_same(remove_const_t, int const *), ""); + static_assert(__is_same(remove_const_t, int const *__restrict), ""); + static_assert(__is_same(remove_const_t, int &), ""); + static_assert(__is_same(remove_const_t, int const &), ""); + static_assert(__is_same(remove_const_t, int &&), ""); + static_assert(__is_same(remove_const_t, int const &&), ""); + static_assert(__is_same(remove_const_t, int()), ""); + static_assert(__is_same(remove_const_t, int (*)()), ""); + static_assert(__is_same(remove_const_t, int (&)()), ""); + + static_assert(__is_same(remove_const_t, S), ""); + static_assert(__is_same(remove_const_t, S), ""); + static_assert(__is_same(remove_const_t, volatile S), ""); + static_assert(__is_same(remove_const_t, S *__restrict), ""); + static_assert(__is_same(remove_const_t, volatile S), ""); + static_assert(__is_same(remove_const_t, S *volatile __restrict), ""); + static_assert(__is_same(remove_const_t, int S::*), ""); + static_assert(__is_same(remove_const_t, int(S::*)()), ""); +} + +template using remove_restrict_t = __remove_restrict(T); + +void check_remove_restrict() { + static_assert(__is_same(remove_restrict_t, void), ""); + static_assert(__is_same(remove_restrict_t, int), ""); + static_assert(__is_same(remove_restrict_t, const int), ""); + static_assert(__is_same(remove_restrict_t, volatile int), ""); + static_assert(__is_same(remove_restrict_t, int *), ""); + static_assert(__is_same(remove_restrict_t, int *const volatile), ""); + static_assert(__is_same(remove_restrict_t, int *), ""); + static_assert(__is_same(remove_restrict_t, int *), ""); + static_assert(__is_same(remove_restrict_t, int &), ""); + static_assert(__is_same(remove_restrict_t, int &), ""); + static_assert(__is_same(remove_restrict_t, int &&), ""); + static_assert(__is_same(remove_restrict_t, int &&), ""); + static_assert(__is_same(remove_restrict_t, int()), ""); + static_assert(__is_same(remove_restrict_t, int (*const volatile)()), ""); + static_assert(__is_same(remove_restrict_t, int (&)()), ""); + + static_assert(__is_same(remove_restrict_t, S), ""); + static_assert(__is_same(remove_restrict_t, const S), ""); + static_assert(__is_same(remove_restrict_t, volatile S), ""); + static_assert(__is_same(remove_restrict_t, S *), ""); + static_assert(__is_same(remove_restrict_t, S *const volatile), ""); + static_assert(__is_same(remove_restrict_t, int S::*), ""); + static_assert(__is_same(remove_restrict_t, int(S::*const volatile)()), ""); +} + +template using remove_volatile_t = __remove_volatile(T); + +void check_remove_volatile() { + static_assert(__is_same(remove_volatile_t, void), ""); + static_assert(__is_same(remove_volatile_t, void), ""); + static_assert(__is_same(remove_volatile_t, int), ""); + static_assert(__is_same(remove_volatile_t, const int), ""); + static_assert(__is_same(remove_volatile_t, int), ""); + static_assert(__is_same(remove_volatile_t, int *__restrict), ""); + static_assert(__is_same(remove_volatile_t, const int), ""); + static_assert(__is_same(remove_volatile_t, int *const __restrict), ""); + static_assert(__is_same(remove_volatile_t, int *), ""); + static_assert(__is_same(remove_volatile_t, int *), ""); + static_assert(__is_same(remove_volatile_t, int volatile *), ""); + static_assert(__is_same(remove_volatile_t, int &), ""); + static_assert(__is_same(remove_volatile_t, int volatile &), ""); + static_assert(__is_same(remove_volatile_t, int &&), ""); + static_assert(__is_same(remove_volatile_t, int volatile &&), ""); + static_assert(__is_same(remove_volatile_t, int()), ""); + static_assert(__is_same(remove_volatile_t, int (*)()), ""); + static_assert(__is_same(remove_volatile_t, int (&)()), ""); + + static_assert(__is_same(remove_volatile_t, S), ""); + static_assert(__is_same(remove_volatile_t, const S), ""); + static_assert(__is_same(remove_volatile_t, S), ""); + static_assert(__is_same(remove_volatile_t, const S), ""); + static_assert(__is_same(remove_volatile_t, int S::*), ""); + static_assert(__is_same(remove_volatile_t, int(S::*)()), ""); +} + +template using remove_cv_t = __remove_cv(T); + +void check_remove_cv() { + static_assert(__is_same(remove_cv_t, void), ""); + static_assert(__is_same(remove_cv_t, void), ""); + static_assert(__is_same(remove_cv_t, int), ""); + static_assert(__is_same(remove_cv_t, int), ""); + static_assert(__is_same(remove_cv_t, int), ""); + static_assert(__is_same(remove_cv_t, int), ""); + static_assert(__is_same(remove_cv_t, int *), ""); + static_assert(__is_same(remove_cv_t, int *), ""); + static_assert(__is_same(remove_cv_t, int const *), ""); + static_assert(__is_same(remove_cv_t, int const *__restrict), ""); + static_assert(__is_same(remove_cv_t, int const *_Nonnull), ""); + static_assert(__is_same(remove_cv_t, int &), ""); + static_assert(__is_same(remove_cv_t, int const volatile &), ""); + static_assert(__is_same(remove_cv_t, int &&), ""); + static_assert(__is_same(remove_cv_t, int const volatile &&), ""); + static_assert(__is_same(remove_cv_t, int()), ""); + static_assert(__is_same(remove_cv_t, int (*)()), ""); + static_assert(__is_same(remove_cv_t, int (&)()), ""); + + static_assert(__is_same(remove_cv_t, S), ""); + static_assert(__is_same(remove_cv_t, S), ""); + static_assert(__is_same(remove_cv_t, S), ""); + static_assert(__is_same(remove_cv_t, S), ""); + static_assert(__is_same(remove_cv_t, int S::*), ""); + static_assert(__is_same(remove_cv_t, int(S::*)()), ""); +} + +template using add_pointer_t = __add_pointer(T); + +void add_pointer() { + static_assert(__is_same(add_pointer_t, void *), ""); + static_assert(__is_same(add_pointer_t, const void *), ""); + static_assert(__is_same(add_pointer_t, volatile void *), ""); + static_assert(__is_same(add_pointer_t, const volatile void *), ""); + static_assert(__is_same(add_pointer_t, int *), ""); + static_assert(__is_same(add_pointer_t, const int *), ""); + static_assert(__is_same(add_pointer_t, volatile int *), ""); + static_assert(__is_same(add_pointer_t, const volatile int *), ""); + static_assert(__is_same(add_pointer_t, int **), ""); + static_assert(__is_same(add_pointer_t, int *), ""); + static_assert(__is_same(add_pointer_t, int *), ""); + static_assert(__is_same(add_pointer_t, int (*)()), ""); + static_assert(__is_same(add_pointer_t, int (**)()), ""); + static_assert(__is_same(add_pointer_t, int (*)()), ""); + + static_assert(__is_same(add_pointer_t, S *), ""); + static_assert(__is_same(add_pointer_t, const S *), ""); + static_assert(__is_same(add_pointer_t, volatile S *), ""); + static_assert(__is_same(add_pointer_t, const volatile S *), ""); + static_assert(__is_same(add_pointer_t, int S::**), ""); + static_assert(__is_same(add_pointer_t, int(S::**)()), ""); + + static_assert(__is_same(add_pointer_t, int __attribute__((address_space(1))) *), ""); + static_assert(__is_same(add_pointer_t, S __attribute__((address_space(2))) *), ""); +} + +template using remove_pointer_t = __remove_pointer(T); + +void remove_pointer() { + static_assert(__is_same(remove_pointer_t, void), ""); + static_assert(__is_same(remove_pointer_t, const void), ""); + static_assert(__is_same(remove_pointer_t, volatile void), ""); + static_assert(__is_same(remove_pointer_t, const volatile void), ""); + static_assert(__is_same(remove_pointer_t, int), ""); + static_assert(__is_same(remove_pointer_t, const int), ""); + static_assert(__is_same(remove_pointer_t, volatile int), ""); + static_assert(__is_same(remove_pointer_t, const volatile int), ""); + static_assert(__is_same(remove_pointer_t, int), ""); + static_assert(__is_same(remove_pointer_t, const int), ""); + static_assert(__is_same(remove_pointer_t, volatile int), ""); + static_assert(__is_same(remove_pointer_t, const volatile int), ""); + static_assert(__is_same(remove_pointer_t, int), ""); + static_assert(__is_same(remove_pointer_t, int), ""); + static_assert(__is_same(remove_pointer_t, int), ""); + static_assert(__is_same(remove_pointer_t, int &), ""); + static_assert(__is_same(remove_pointer_t, int &&), ""); + static_assert(__is_same(remove_pointer_t, int()), ""); + static_assert(__is_same(remove_pointer_t, int()), ""); + static_assert(__is_same(remove_pointer_t, int (&)()), ""); + + static_assert(__is_same(remove_pointer_t, S), ""); + static_assert(__is_same(remove_pointer_t, const S), ""); + static_assert(__is_same(remove_pointer_t, volatile S), ""); + static_assert(__is_same(remove_pointer_t, const volatile S), ""); + static_assert(__is_same(remove_pointer_t, int S::*), ""); + static_assert(__is_same(remove_pointer_t, int(S::*)()), ""); + + static_assert(__is_same(remove_pointer_t, int __attribute__((address_space(1)))), ""); + static_assert(__is_same(remove_pointer_t, S __attribute__((address_space(2)))), ""); + + static_assert(__is_same(remove_pointer_t, int (^)(char)), ""); +} + +template using add_lvalue_reference_t = __add_lvalue_reference(T); + +void add_lvalue_reference() { + static_assert(__is_same(add_lvalue_reference_t, void), ""); + static_assert(__is_same(add_lvalue_reference_t, const void), ""); + static_assert(__is_same(add_lvalue_reference_t, volatile void), ""); + static_assert(__is_same(add_lvalue_reference_t, const volatile void), ""); + static_assert(__is_same(add_lvalue_reference_t, int &), ""); + static_assert(__is_same(add_lvalue_reference_t, const int &), ""); + static_assert(__is_same(add_lvalue_reference_t, volatile int &), ""); + static_assert(__is_same(add_lvalue_reference_t, const volatile int &), ""); + static_assert(__is_same(add_lvalue_reference_t, int *&), ""); + static_assert(__is_same(add_lvalue_reference_t, int &), ""); + static_assert(__is_same(add_lvalue_reference_t, int &), ""); // reference collapsing + static_assert(__is_same(add_lvalue_reference_t, int (&)()), ""); + static_assert(__is_same(add_lvalue_reference_t, int (*&)()), ""); + static_assert(__is_same(add_lvalue_reference_t, int (&)()), ""); + + static_assert(__is_same(add_lvalue_reference_t, S &), ""); + static_assert(__is_same(add_lvalue_reference_t, const S &), ""); + static_assert(__is_same(add_lvalue_reference_t, volatile S &), ""); + static_assert(__is_same(add_lvalue_reference_t, const volatile S &), ""); + static_assert(__is_same(add_lvalue_reference_t, int S::*&), ""); + static_assert(__is_same(add_lvalue_reference_t, int(S::*&)()), ""); +} + +template using add_rvalue_reference_t = __add_rvalue_reference(T); + +void add_rvalue_reference() { + static_assert(__is_same(add_rvalue_reference_t, void), ""); + static_assert(__is_same(add_rvalue_reference_t, const void), ""); + static_assert(__is_same(add_rvalue_reference_t, volatile void), ""); + static_assert(__is_same(add_rvalue_reference_t, const volatile void), ""); + static_assert(__is_same(add_rvalue_reference_t, int &&), ""); + static_assert(__is_same(add_rvalue_reference_t, const int &&), ""); + static_assert(__is_same(add_rvalue_reference_t, volatile int &&), ""); + static_assert(__is_same(add_rvalue_reference_t, const volatile int &&), ""); + static_assert(__is_same(add_rvalue_reference_t, int *&&), ""); + static_assert(__is_same(add_rvalue_reference_t, int &), ""); // reference collapsing + static_assert(__is_same(add_rvalue_reference_t, int &&), ""); + static_assert(__is_same(add_rvalue_reference_t, int(&&)()), ""); + static_assert(__is_same(add_rvalue_reference_t, int (*&&)()), ""); + static_assert(__is_same(add_rvalue_reference_t, int (&)()), ""); // reference collapsing + + static_assert(__is_same(add_rvalue_reference_t, S &&), ""); + static_assert(__is_same(add_rvalue_reference_t, const S &&), ""); + static_assert(__is_same(add_rvalue_reference_t, volatile S &&), ""); + static_assert(__is_same(add_rvalue_reference_t, const volatile S &&), ""); + static_assert(__is_same(add_rvalue_reference_t, int S::*&&), ""); + static_assert(__is_same(add_rvalue_reference_t, int(S::* &&)()), ""); +} + +template using remove_reference_t = __remove_reference(T); + +void check_remove_reference() { + static_assert(__is_same(remove_reference_t, void), ""); + static_assert(__is_same(remove_reference_t, const volatile void), ""); + static_assert(__is_same(remove_reference_t, int), ""); + static_assert(__is_same(remove_reference_t, const int), ""); + static_assert(__is_same(remove_reference_t, volatile int), ""); + static_assert(__is_same(remove_reference_t, const volatile int), ""); + static_assert(__is_same(remove_reference_t, int *), ""); + static_assert(__is_same(remove_reference_t, int *const volatile), ""); + static_assert(__is_same(remove_reference_t, int const *const volatile), ""); + static_assert(__is_same(remove_reference_t, int), ""); + static_assert(__is_same(remove_reference_t, int const volatile), ""); + static_assert(__is_same(remove_reference_t, int), ""); + static_assert(__is_same(remove_reference_t, int const volatile), ""); + static_assert(__is_same(remove_reference_t, int()), ""); + static_assert(__is_same(remove_reference_t, int (*const volatile)()), ""); + static_assert(__is_same(remove_reference_t, int()), ""); + + static_assert(__is_same(remove_reference_t, S), ""); + static_assert(__is_same(remove_reference_t, S), ""); + static_assert(__is_same(remove_reference_t, S), ""); + static_assert(__is_same(remove_reference_t, const S), ""); + static_assert(__is_same(remove_reference_t, const S), ""); + static_assert(__is_same(remove_reference_t, const S), ""); + static_assert(__is_same(remove_reference_t, volatile S), ""); + static_assert(__is_same(remove_reference_t, volatile S), ""); + static_assert(__is_same(remove_reference_t, volatile S), ""); + static_assert(__is_same(remove_reference_t, const volatile S), ""); + static_assert(__is_same(remove_reference_t, const volatile S), ""); + static_assert(__is_same(remove_reference_t, const volatile S), ""); + static_assert(__is_same(remove_reference_t, int S::*const volatile), ""); + static_assert(__is_same(remove_reference_t, int(S::*const volatile)()), ""); + static_assert(__is_same(remove_reference_t, int(S::*const volatile)() &), ""); +} + +template using remove_cvref_t = __remove_cvref(T); + +void check_remove_cvref() { + static_assert(__is_same(remove_cvref_t, void), ""); + static_assert(__is_same(remove_cvref_t, void), ""); + static_assert(__is_same(remove_cvref_t, int), ""); + static_assert(__is_same(remove_cvref_t, int), ""); + static_assert(__is_same(remove_cvref_t, int), ""); + static_assert(__is_same(remove_cvref_t, int), ""); + static_assert(__is_same(remove_cvref_t, int *), ""); + static_assert(__is_same(remove_cvref_t, int *), ""); + static_assert(__is_same(remove_cvref_t, int const *), ""); + static_assert(__is_same(remove_cvref_t, int const *__restrict), ""); + static_assert(__is_same(remove_cvref_t, int const *_Nonnull), ""); + static_assert(__is_same(remove_cvref_t, int), ""); + static_assert(__is_same(remove_cvref_t, int), ""); + static_assert(__is_same(remove_cvref_t, int), ""); + static_assert(__is_same(remove_cvref_t, int), ""); + static_assert(__is_same(remove_cvref_t, int()), ""); + static_assert(__is_same(remove_cvref_t, int (*)()), ""); + static_assert(__is_same(remove_cvref_t, int()), ""); + + static_assert(__is_same(remove_cvref_t, S), ""); + static_assert(__is_same(remove_cvref_t, S), ""); + static_assert(__is_same(remove_cvref_t, S), ""); + static_assert(__is_same(remove_cvref_t, S), ""); + static_assert(__is_same(remove_cvref_t, S), ""); + static_assert(__is_same(remove_cvref_t, S), ""); + static_assert(__is_same(remove_cvref_t, S), ""); + static_assert(__is_same(remove_cvref_t, S), ""); + static_assert(__is_same(remove_cvref_t, S), ""); + static_assert(__is_same(remove_cvref_t, S), ""); + static_assert(__is_same(remove_cvref_t, S), ""); + static_assert(__is_same(remove_cvref_t, S), ""); + static_assert(__is_same(remove_cvref_t, int S::*), ""); + static_assert(__is_same(remove_cvref_t, int(S::*)()), ""); + static_assert(__is_same(remove_cvref_t, int(S::*)() &), ""); + static_assert(__is_same(remove_cvref_t, int(S::*)() &&), ""); +} + +template using decay_t = __decay(T); +template struct dne; + +void check_decay() { + static_assert(__is_same(decay_t, void), ""); + static_assert(__is_same(decay_t, void), ""); + static_assert(__is_same(decay_t, int), ""); + static_assert(__is_same(decay_t, int), ""); + static_assert(__is_same(decay_t, int), ""); + static_assert(__is_same(decay_t, int), ""); + static_assert(__is_same(decay_t, int *), ""); + static_assert(__is_same(decay_t, int *), ""); + static_assert(__is_same(decay_t, int *), ""); + static_assert(__is_same(decay_t, int const *), ""); + static_assert(__is_same(decay_t, int const *), ""); + static_assert(__is_same(decay_t, int), ""); + static_assert(__is_same(decay_t, int), ""); + static_assert(__is_same(decay_t, int), ""); + static_assert(__is_same(decay_t, int), ""); + static_assert(__is_same(decay_t, int (*)()), ""); + static_assert(__is_same(decay_t, int (*)()), ""); + static_assert(__is_same(decay_t, int (*)()), ""); + static_assert(__is_same(decay_t, int (*)()), ""); + static_assert(__is_same(decay_t, int (*)()), ""); + static_assert(__is_same(decay_t, int (*)()), ""); + static_assert(__is_same(decay_t, int *), ""); + static_assert(__is_same(decay_t, int *), ""); + + static_assert(__is_same(decay_t, S), ""); + static_assert(__is_same(decay_t, S), ""); + static_assert(__is_same(decay_t, S), ""); + static_assert(__is_same(decay_t, S), ""); + static_assert(__is_same(decay_t, S), ""); + static_assert(__is_same(decay_t, S), ""); + static_assert(__is_same(decay_t, S), ""); + static_assert(__is_same(decay_t, S), ""); + static_assert(__is_same(decay_t, S), ""); + static_assert(__is_same(decay_t, S), ""); + static_assert(__is_same(decay_t, S), ""); + static_assert(__is_same(decay_t, S), ""); + static_assert(__is_same(decay_t, int S::*), ""); + static_assert(__is_same(decay_t, int(S::*)()), ""); + static_assert(__is_same(decay_t, int S::*), ""); + static_assert(__is_same(decay_t, int(S::*)()), ""); + static_assert(__is_same(decay_t, int S::*), ""); +} + +template struct CheckAbominableFunction {}; +template +struct CheckAbominableFunction { + static void checks() { + static_assert(__is_same(add_lvalue_reference_t, M), ""); + static_assert(__is_same(add_pointer_t, M), ""); + static_assert(__is_same(add_rvalue_reference_t, M), ""); + static_assert(__is_same(decay_t, M), ""); + static_assert(__is_same(remove_const_t, M), ""); + static_assert(__is_same(remove_volatile_t, M), ""); + static_assert(__is_same(remove_cv_t, M), ""); + static_assert(__is_same(remove_cvref_t, M), ""); + static_assert(__is_same(remove_pointer_t, M), ""); + static_assert(__is_same(remove_reference_t, M), ""); + } +}; + +void check_abominable_function() { + { CheckAbominableFunction x; } + { CheckAbominableFunction x; } + { CheckAbominableFunction x; } + { CheckAbominableFunction x; } + { CheckAbominableFunction x; } + { CheckAbominableFunction x; } + { CheckAbominableFunction x; } + { CheckAbominableFunction x; } + { CheckAbominableFunction x; } + { CheckAbominableFunction x; } + { CheckAbominableFunction x; } +} + +template using make_signed_t = __make_signed(T); +template +void check_make_signed() { + static_assert(__is_same(make_signed_t, Expected), ""); + static_assert(__is_same(make_signed_t, const Expected), ""); + static_assert(__is_same(make_signed_t, volatile Expected), ""); + static_assert(__is_same(make_signed_t, const volatile Expected), ""); +} + +#if defined(__ILP32__) || defined(__LLP64__) + using Int64 = long long; + using UInt64 = unsigned long long; +#elif defined(__LP64__) || defined(__ILP64__) || defined(__SILP64__) + using Int64 = long; + using UInt64 = unsigned long; +#else +#error Programming model currently unsupported; please add a new entry. +#endif + +enum UnscopedBool : bool {}; // deliberately char +enum class ScopedBool : bool {}; // deliberately char +enum UnscopedChar : char {}; // deliberately char +enum class ScopedChar : char {}; // deliberately char +enum UnscopedUChar : unsigned char {}; +enum class ScopedUChar : unsigned char {}; +enum UnscopedLongLong : long long {}; +enum UnscopedULongLong : unsigned long long {}; +enum class ScopedLongLong : long long {}; +enum class ScopedULongLong : unsigned long long {}; +enum class UnscopedInt128 : __int128 {}; +enum class ScopedInt128 : __int128 {}; +enum class UnscopedUInt128 : unsigned __int128 {}; +enum class ScopedUInt128 : unsigned __int128 {}; +enum UnscopedBit : unsigned _BitInt(1) {}; +enum ScopedBit : unsigned _BitInt(1) {}; +enum UnscopedIrregular : _BitInt(21) {}; +enum UnscopedUIrregular : unsigned _BitInt(21) {}; +enum class ScopedIrregular : _BitInt(21) {}; +enum class ScopedUIrregular : unsigned _BitInt(21) {}; + +void make_signed() { + check_make_signed(); + check_make_signed(); + check_make_signed(); + check_make_signed(); + check_make_signed(); + check_make_signed(); + check_make_signed(); + check_make_signed(); + check_make_signed(); + check_make_signed(); + check_make_signed(); + check_make_signed<__int128, __int128>(); + check_make_signed<__uint128_t, __int128>(); + check_make_signed<_BitInt(65), _BitInt(65)>(); + check_make_signed(); + + check_make_signed(); +#if __cplusplus >= 202002L + check_make_signed(); +#endif +#if __cplusplus >= 201103L + check_make_signed(); + check_make_signed(); +#endif + + check_make_signed(); + check_make_signed(); + check_make_signed(); + check_make_signed(); + + check_make_signed(); + check_make_signed(); + check_make_signed(); + check_make_signed(); + + check_make_signed(); + check_make_signed(); + check_make_signed(); + check_make_signed(); + + check_make_signed(); + check_make_signed(); + check_make_signed(); + check_make_signed(); + + { using ExpectedError = __make_signed(bool); } + // expected-error@*:*{{'make_signed' is only compatible with non-bool integers and enum types, but was given 'bool'}} + { using ExpectedError = __make_signed(UnscopedBool); } + // expected-error@*:*{{'make_signed' is only compatible with non-bool integers and enum types, but was given 'UnscopedBool' whose underlying type is 'bool'}} + { using ExpectedError = __make_signed(ScopedBool); } + // expected-error@*:*{{'make_signed' is only compatible with non-bool integers and enum types, but was given 'ScopedBool' whose underlying type is 'bool'}} + { using ExpectedError = __make_signed(unsigned _BitInt(1)); } + // expected-error@*:*{{'make_signed' is only compatible with non-_BitInt(1) integers and enum types, but was given 'unsigned _BitInt(1)'}} + { using ExpectedError = __make_signed(UnscopedBit); } + // expected-error@*:*{{'make_signed' is only compatible with non-_BitInt(1) integers and enum types, but was given 'UnscopedBit' whose underlying type is 'unsigned _BitInt(1)'}} + { using ExpectedError = __make_signed(ScopedBit); } + // expected-error@*:*{{'make_signed' is only compatible with non-_BitInt(1) integers and enum types, but was given 'ScopedBit' whose underlying type is 'unsigned _BitInt(1)'}} + { using ExpectedError = __make_signed(int[]); } + // expected-error@*:*{{'make_signed' is only compatible with non-bool integers and enum types, but was given 'int[]'}} + { using ExpectedError = __make_signed(int[5]); } + // expected-error@*:*{{'make_signed' is only compatible with non-bool integers and enum types, but was given 'int[5]'}} + { using ExpectedError = __make_signed(void); } + // expected-error@*:*{{'make_signed' is only compatible with non-bool integers and enum types, but was given 'void'}} + { using ExpectedError = __make_signed(int *); } + // expected-error@*:*{{'make_signed' is only compatible with non-bool integers and enum types, but was given 'int *'}} + { using ExpectedError = __make_signed(int &); } + // expected-error@*:*{{'make_signed' is only compatible with non-bool integers and enum types, but was given 'int &'}} + { using ExpectedError = __make_signed(int &&); } + // expected-error@*:*{{'make_signed' is only compatible with non-bool integers and enum types, but was given 'int &&'}} + { using ExpectedError = __make_signed(float); } + // expected-error@*:*{{'make_signed' is only compatible with non-bool integers and enum types, but was given 'float'}} + { using ExpectedError = __make_signed(double); } + // expected-error@*:*{{'make_signed' is only compatible with non-bool integers and enum types, but was given 'double'}} + { using ExpectedError = __make_signed(long double); } + // expected-error@*:*{{'make_signed' is only compatible with non-bool integers and enum types, but was given 'long double'}} + { using ExpectedError = __make_signed(S); } + // expected-error@*:*{{'make_signed' is only compatible with non-bool integers and enum types, but was given 'S'}} + { using ExpectedError = __make_signed(S *); } + // expected-error@*:*{{'make_signed' is only compatible with non-bool integers and enum types, but was given 'S *'}} + { using ExpectedError = __make_signed(int S::*); } + // expected-error@*:*{{'make_signed' is only compatible with non-bool integers and enum types, but was given 'int S::*'}} + { using ExpectedError = __make_signed(int(S::*)()); } + // expected-error@*:*{{'make_signed' is only compatible with non-bool integers and enum types, but was given 'int (S::*)()'}} +} + +template +using make_unsigned_t = __make_unsigned(T); + +template +void check_make_unsigned() { + static_assert(__is_same(make_unsigned_t, Expected), ""); + static_assert(__is_same(make_unsigned_t, const Expected), ""); + static_assert(__is_same(make_unsigned_t, volatile Expected), ""); + static_assert(__is_same(make_unsigned_t, const volatile Expected), ""); +} + +void make_unsigned() { + check_make_unsigned(); + check_make_unsigned(); + check_make_unsigned(); + check_make_unsigned(); + check_make_unsigned(); + check_make_unsigned(); + check_make_unsigned(); + check_make_unsigned(); + check_make_unsigned(); + check_make_unsigned(); + check_make_unsigned(); + check_make_unsigned<__int128, __uint128_t>(); + check_make_unsigned<__uint128_t, __uint128_t>(); + check_make_unsigned<_BitInt(65), unsigned _BitInt(65)>(); + check_make_unsigned(); + + check_make_unsigned(); +#if __cplusplus >= 202002L + check_make_unsigned(); +#endif +#if __cplusplus >= 201103L + check_make_unsigned(); + check_make_unsigned(); +#endif + + check_make_unsigned(); + check_make_unsigned(); + check_make_unsigned(); + check_make_unsigned(); + + check_make_unsigned(); + check_make_unsigned(); + check_make_unsigned(); + check_make_unsigned(); + + check_make_unsigned(); + check_make_unsigned(); + check_make_unsigned(); + check_make_unsigned(); + + check_make_unsigned(); + check_make_unsigned(); + check_make_unsigned(); + check_make_unsigned(); + + { using ExpectedError = __make_unsigned(bool); } + // expected-error@*:*{{'make_unsigned' is only compatible with non-bool integers and enum types, but was given 'bool'}} + { using ExpectedError = __make_unsigned(UnscopedBool); } + // expected-error@*:*{{'make_unsigned' is only compatible with non-bool integers and enum types, but was given 'UnscopedBool' whose underlying type is 'bool'}} + { using ExpectedError = __make_unsigned(ScopedBool); } + // expected-error@*:*{{'make_unsigned' is only compatible with non-bool integers and enum types, but was given 'ScopedBool' whose underlying type is 'bool'}} + { using ExpectedError = __make_unsigned(unsigned _BitInt(1)); } + // expected-error@*:*{{'make_unsigned' is only compatible with non-_BitInt(1) integers and enum types, but was given 'unsigned _BitInt(1)'}} + { using ExpectedError = __make_unsigned(UnscopedBit); } + // expected-error@*:*{{'make_unsigned' is only compatible with non-_BitInt(1) integers and enum types, but was given 'UnscopedBit'}} + { using ExpectedError = __make_unsigned(ScopedBit); } + // expected-error@*:*{{'make_unsigned' is only compatible with non-_BitInt(1) integers and enum types, but was given 'ScopedBit'}} + { using ExpectedError = __make_unsigned(int[]); } + // expected-error@*:*{{'make_unsigned' is only compatible with non-bool integers and enum types, but was given 'int[]'}} + { using ExpectedError = __make_unsigned(int[5]); } + // expected-error@*:*{{'make_unsigned' is only compatible with non-bool integers and enum types, but was given 'int[5]'}} + { using ExpectedError = __make_unsigned(void); } + // expected-error@*:*{{'make_unsigned' is only compatible with non-bool integers and enum types, but was given 'void'}} + { using ExpectedError = __make_unsigned(int *); } + // expected-error@*:*{{'make_unsigned' is only compatible with non-bool integers and enum types, but was given 'int *'}} + { using ExpectedError = __make_unsigned(int &); } + // expected-error@*:*{{'make_unsigned' is only compatible with non-bool integers and enum types, but was given 'int &'}} + { using ExpectedError = __make_unsigned(int &&); } + // expected-error@*:*{{'make_unsigned' is only compatible with non-bool integers and enum types, but was given 'int &&'}} + { using ExpectedError = __make_unsigned(float); } + // expected-error@*:*{{'make_unsigned' is only compatible with non-bool integers and enum types, but was given 'float'}} + { using ExpectedError = __make_unsigned(double); } + // expected-error@*:*{{'make_unsigned' is only compatible with non-bool integers and enum types, but was given 'double'}} + { using ExpectedError = __make_unsigned(long double); } + // expected-error@*:*{{'make_unsigned' is only compatible with non-bool integers and enum types, but was given 'long double'}} + { using ExpectedError = __make_unsigned(S); } + // expected-error@*:*{{'make_unsigned' is only compatible with non-bool integers and enum types, but was given 'S'}} + { using ExpectedError = __make_unsigned(S *); } + // expected-error@*:*{{'make_unsigned' is only compatible with non-bool integers and enum types, but was given 'S *'}} + { using ExpectedError = __make_unsigned(int S::*); } + // expected-error@*:*{{'make_unsigned' is only compatible with non-bool integers and enum types, but was given 'int S::*'}} + { using ExpectedError = __make_unsigned(int(S::*)()); } + // expected-error@*:*{{'make_unsigned' is only compatible with non-bool integers and enum types, but was given 'int (S::*)()'}} +} + +template using remove_extent_t = __remove_extent(T); + +void remove_extent() { + static_assert(__is_same(remove_extent_t, void), ""); + static_assert(__is_same(remove_extent_t, int), ""); + static_assert(__is_same(remove_extent_t, int), ""); + static_assert(__is_same(remove_extent_t, int), ""); + static_assert(__is_same(remove_extent_t, int[2]), ""); + static_assert(__is_same(remove_extent_t, int[2]), ""); + static_assert(__is_same(remove_extent_t, const int), ""); + static_assert(__is_same(remove_extent_t, const int), ""); + static_assert(__is_same(remove_extent_t, const int[2]), ""); + static_assert(__is_same(remove_extent_t, const int[2]), ""); + static_assert(__is_same(remove_extent_t, volatile int), ""); + static_assert(__is_same(remove_extent_t, volatile int), ""); + static_assert(__is_same(remove_extent_t, volatile int[2]), ""); + static_assert(__is_same(remove_extent_t, volatile int[2]), ""); + static_assert(__is_same(remove_extent_t, const volatile int), ""); + static_assert(__is_same(remove_extent_t, const volatile int), ""); + static_assert(__is_same(remove_extent_t, const volatile int[2]), ""); + static_assert(__is_same(remove_extent_t, const volatile int[2]), ""); + static_assert(__is_same(remove_extent_t, int *), ""); + static_assert(__is_same(remove_extent_t, int &), ""); + static_assert(__is_same(remove_extent_t, int &&), ""); + static_assert(__is_same(remove_extent_t, int()), ""); + static_assert(__is_same(remove_extent_t, int (*)()), ""); + static_assert(__is_same(remove_extent_t, int (&)()), ""); + + static_assert(__is_same(remove_extent_t, S), ""); + static_assert(__is_same(remove_extent_t, int S::*), ""); + static_assert(__is_same(remove_extent_t, int(S::*)()), ""); + + using SomeArray = int[1][2]; + static_assert(__is_same(remove_extent_t, const int[2]), ""); +} + +template using remove_all_extents_t = __remove_all_extents(T); + +void remove_all_extents() { + static_assert(__is_same(remove_all_extents_t, void), ""); + static_assert(__is_same(remove_all_extents_t, int), ""); + static_assert(__is_same(remove_all_extents_t, const int), ""); + static_assert(__is_same(remove_all_extents_t, volatile int), ""); + static_assert(__is_same(remove_all_extents_t, const volatile int), ""); + static_assert(__is_same(remove_all_extents_t, int), ""); + static_assert(__is_same(remove_all_extents_t, int), ""); + static_assert(__is_same(remove_all_extents_t, int), ""); + static_assert(__is_same(remove_all_extents_t, int), ""); + static_assert(__is_same(remove_all_extents_t, const int), ""); + static_assert(__is_same(remove_all_extents_t, const int), ""); + static_assert(__is_same(remove_all_extents_t, const int), ""); + static_assert(__is_same(remove_all_extents_t, const int), ""); + static_assert(__is_same(remove_all_extents_t, volatile int), ""); + static_assert(__is_same(remove_all_extents_t, volatile int), ""); + static_assert(__is_same(remove_all_extents_t, volatile int), ""); + static_assert(__is_same(remove_all_extents_t, volatile int), ""); + static_assert(__is_same(remove_all_extents_t, const volatile int), ""); + static_assert(__is_same(remove_all_extents_t, const volatile int), ""); + static_assert(__is_same(remove_all_extents_t, const volatile int), ""); + static_assert(__is_same(remove_all_extents_t, const volatile int), ""); + static_assert(__is_same(remove_all_extents_t, int *), ""); + static_assert(__is_same(remove_all_extents_t, int &), ""); + static_assert(__is_same(remove_all_extents_t, int &&), ""); + static_assert(__is_same(remove_all_extents_t, int()), ""); + static_assert(__is_same(remove_all_extents_t, int (*)()), ""); + static_assert(__is_same(remove_all_extents_t, int (&)()), ""); + + static_assert(__is_same(remove_all_extents_t, S), ""); + static_assert(__is_same(remove_all_extents_t, int S::*), ""); + static_assert(__is_same(remove_all_extents_t, int(S::*)()), ""); + + using SomeArray = int[1][2]; + static_assert(__is_same(remove_all_extents_t, const int), ""); +} diff --git a/clang/utils/ClangVisualizers/clang.natvis b/clang/utils/ClangVisualizers/clang.natvis --- a/clang/utils/ClangVisualizers/clang.natvis +++ b/clang/utils/ClangVisualizers/clang.natvis @@ -2,7 +2,7 @@ @@ -11,8 +11,8 @@ {(clang::Decl::Kind)DeclContextBits.DeclKind,en}Decl @@ -201,7 +201,7 @@ {{InheritedInitializer}} = {this,view(DefaultArg)na} - {*this,view(TorC)} {*this,view(MaybeEllipses)}{Name,view(cpp)} {this,view(Initializer)na} + {*this,view(TorC)} {*this,view(MaybeEllipses)}{Name,view(cpp)} {this,view(Initializer)na} {*TemplatedDecl,view(cpp)} @@ -694,7 +694,7 @@ C++ Constructor {{{(clang::detail::CXXSpecialNameExtra *)(Ptr & ~PtrMask),view(cpp)na}}} C++ Destructor {{*(clang::detail::CXXSpecialNameExtra *)(Ptr & ~PtrMask)}} C++ Conversion function {{*(clang::detail::CXXSpecialNameExtra *)(Ptr & ~PtrMask)}} - C++ Operator {{*(clang::detail::CXXOperatorIdName *)(Ptr & ~PtrMask)}} + C++ Operator {{*(clang::detail::CXXOperatorIdName *)(Ptr & ~PtrMask)}} {*(clang::detail::DeclarationNameExtra *)(Ptr & ~PtrMask),view(cpp)} {{Extra ({*(clang::detail::DeclarationNameExtra *)(Ptr & ~PtrMask)})}} @@ -706,7 +706,7 @@ *(clang::detail::CXXSpecialNameExtra *)(Ptr & ~PtrMask),na *(clang::detail::CXXSpecialNameExtra *)(Ptr & ~PtrMask),na *(clang::detail::CXXSpecialNameExtra *)(Ptr & ~PtrMask),na - *(clang::detail::CXXOperatorIdName *)(Ptr & ~PtrMask),na + *(clang::detail::CXXOperatorIdName *)(Ptr & ~PtrMask),na (clang::detail::DeclarationNameExtra *)(Ptr & ~PtrMask),na @@ -718,7 +718,7 @@ {(CXXDeductionGuideNameExtra *)this,nand} C++ Literal operator - C++ Using directive + C++ Using directive {(clang::detail::DeclarationNameExtra::ExtraKind)ExtraKindOrNumArgs,en}{" ",sb}{*this,view(cpp)} (CXXDeductionGuideNameExtra *)this @@ -809,7 +809,7 @@ [{this,view(default)na}{this,view(capture0)na}] - + , [{TypeRep}] @@ -823,7 +823,7 @@ (clang::DeclSpec::SCS)StorageClassSpec (clang::TypeSpecifierType)TypeSpecType - + TypeRep