Index: include/clang/AST/ASTContext.h =================================================================== --- include/clang/AST/ASTContext.h +++ include/clang/AST/ASTContext.h @@ -189,8 +189,8 @@ llvm::FoldingSet PackExpansionTypes; mutable llvm::FoldingSet ObjCObjectTypes; mutable llvm::FoldingSet ObjCObjectPointerTypes; - mutable llvm::FoldingSet - DependentUnaryTransformTypes; + mutable llvm::FoldingSet + DependentTransformTraitTypes; mutable llvm::FoldingSet AutoTypes; mutable llvm::FoldingSet DeducedTemplateSpecializationTypes; @@ -1476,9 +1476,10 @@ /// \brief C++11 decltype. QualType getDecltypeType(Expr *e, QualType UnderlyingType) const; - /// \brief Unary type transforms - QualType getUnaryTransformType(QualType BaseType, QualType UnderlyingType, - UnaryTransformType::UTTKind UKind) const; + /// \brief type trait transformations + QualType getTransformTraitType(ArrayRef ArgTypes, + QualType TransformedType, + TransformTraitType::TTKind TKind) const; /// \brief C++11 deduced auto type. QualType getAutoType(QualType DeducedType, AutoTypeKeyword Keyword, Index: include/clang/AST/CanonicalType.h =================================================================== --- include/clang/AST/CanonicalType.h +++ include/clang/AST/CanonicalType.h @@ -538,11 +538,15 @@ }; template <> -struct CanProxyAdaptor - : public CanProxyBase { - LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getBaseType) - LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getUnderlyingType) - LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(UnaryTransformType::UTTKind, getUTTKind) +struct CanProxyAdaptor + : public CanProxyBase { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getTransformedType) + + CanQualType getArg(unsigned i) const { + return CanQualType::CreateUnsafe(this->getTypePtr()->getArg(i)); + } + + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(TransformTraitType::TTKind, getTTKind) }; template<> Index: include/clang/AST/RecursiveASTVisitor.h =================================================================== --- include/clang/AST/RecursiveASTVisitor.h +++ include/clang/AST/RecursiveASTVisitor.h @@ -1032,9 +1032,11 @@ DEF_TRAVERSE_TYPE(DecltypeType, { TRY_TO(TraverseStmt(T->getUnderlyingExpr())); }) -DEF_TRAVERSE_TYPE(UnaryTransformType, { - TRY_TO(TraverseType(T->getBaseType())); - TRY_TO(TraverseType(T->getUnderlyingType())); +DEF_TRAVERSE_TYPE(TransformTraitType, { + for (auto Ty : T->getArgs()) { + TRY_TO(TraverseType(Ty)); + } + TRY_TO(TraverseType(T->getTransformedType())); }) DEF_TRAVERSE_TYPE(AutoType, { TRY_TO(TraverseType(T->getDeducedType())); }) @@ -1267,8 +1269,10 @@ TRY_TO(TraverseStmt(TL.getTypePtr()->getUnderlyingExpr())); }) -DEF_TRAVERSE_TYPELOC(UnaryTransformType, { - TRY_TO(TraverseTypeLoc(TL.getUnderlyingTInfo()->getTypeLoc())); +DEF_TRAVERSE_TYPELOC(TransformTraitType, { + for (auto *TyInfo : TL.getArgTInfo()) { + TRY_TO(TraverseTypeLoc(TyInfo->getTypeLoc())); + } }) DEF_TRAVERSE_TYPELOC(AutoType, { Index: include/clang/AST/Type.h =================================================================== --- include/clang/AST/Type.h +++ include/clang/AST/Type.h @@ -1614,6 +1614,15 @@ unsigned Keyword : 2; }; + class TransformTraitTypeBitfields { + friend class TransformTraitType; + + unsigned : NumTypeBits; + + /// The transformation trait kind + unsigned TTKind : 1; + }; + union { TypeBitfields TypeBits; ArrayTypeBitfields ArrayTypeBits; @@ -1625,6 +1634,7 @@ ReferenceTypeBitfields ReferenceTypeBits; TypeWithKeywordBitfields TypeWithKeywordBits; VectorTypeBitfields VectorTypeBits; + TransformTraitTypeBitfields TransformTraitTypeBits; }; private: @@ -3971,38 +3981,42 @@ }; /// A unary type transform, which is a type constructed from another. -class UnaryTransformType : public Type { +class TransformTraitType : public Type { public: - enum UTTKind { - EnumUnderlyingType - }; + enum TTKind { EnumUnderlyingType }; private: /// The untransformed type. - QualType BaseType; + SmallVector ArgTypes; /// The transformed type if not dependent, otherwise the same as BaseType. - QualType UnderlyingType; - - UTTKind UKind; + QualType TransformedType; protected: friend class ASTContext; - UnaryTransformType(QualType BaseTy, QualType UnderlyingTy, UTTKind UKind, - QualType CanonicalTy); + TransformTraitType(ArrayRef ArgTy, QualType TransformedTy, + TTKind TKind, QualType CanonicalTy); public: bool isSugared() const { return !isDependentType(); } - QualType desugar() const { return UnderlyingType; } + QualType desugar() const { return TransformedType; } - QualType getUnderlyingType() const { return UnderlyingType; } - QualType getBaseType() const { return BaseType; } + unsigned getNumArgs() const { return ArgTypes.size(); } + ArrayRef getArgs() const { return ArgTypes; } - UTTKind getUTTKind() const { return UKind; } + QualType getTransformedType() const { return TransformedType; } + QualType getArg(unsigned N) const { + assert(N < ArgTypes.size() && "invalid index"); + return ArgTypes[N]; + } + + TTKind getTTKind() const { + return static_cast(TransformTraitTypeBits.TTKind); + } static bool classof(const Type *T) { - return T->getTypeClass() == UnaryTransform; + return T->getTypeClass() == TransformTrait; } }; @@ -4011,21 +4025,23 @@ /// /// This class is used internally by the ASTContext to manage /// canonical, dependent types, only. Clients will only see instances -/// of this class via UnaryTransformType nodes. -class DependentUnaryTransformType : public UnaryTransformType, +/// of this class via TransformTraitType nodes. +class DependentTransformTraitType : public TransformTraitType, public llvm::FoldingSetNode { public: - DependentUnaryTransformType(const ASTContext &C, QualType BaseType, - UTTKind UKind); + DependentTransformTraitType(const ASTContext &C, ArrayRef ArgTypes, + TTKind TKind); void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getBaseType(), getUTTKind()); + Profile(ID, getArgs(), getTTKind()); } - static void Profile(llvm::FoldingSetNodeID &ID, QualType BaseType, - UTTKind UKind) { - ID.AddPointer(BaseType.getAsOpaquePtr()); - ID.AddInteger((unsigned)UKind); + static void Profile(llvm::FoldingSetNodeID &ID, ArrayRef ArgTypes, + TTKind TKind) { + ID.AddInteger((unsigned)ArgTypes.size()); + for (auto Ty : ArgTypes) + ID.AddPointer(Ty.getAsOpaquePtr()); + ID.AddInteger((unsigned)TKind); } }; Index: include/clang/AST/TypeLoc.h =================================================================== --- include/clang/AST/TypeLoc.h +++ include/clang/AST/TypeLoc.h @@ -1029,6 +1029,10 @@ getTypeArgLocArray()[i] = TInfo; } + ArrayRef getTypeArgTInfoRef() const { + return llvm::makeArrayRef(getTypeArgLocArray(), getNumTypeArgs()); + } + SourceLocation getProtocolLAngleLoc() const { return this->getLocalData()->ProtocolLAngleLoc; } @@ -1919,17 +1923,20 @@ Expr *getUnderlyingExpr() const { return getTypePtr()->getUnderlyingExpr(); } }; -struct UnaryTransformTypeLocInfo { +struct TransformTraitTypeLocInfo { // FIXME: While there's only one unary transform right now, future ones may // need different representations SourceLocation KWLoc, LParenLoc, RParenLoc; - TypeSourceInfo *UnderlyingTInfo; }; -class UnaryTransformTypeLoc : public ConcreteTypeLoc { +class TransformTraitTypeLoc + : public ConcreteTypeLoc { + // TypeSourceInfo*'s are stored after Info, one for each type argument. + TypeSourceInfo **getArgLocArray() const { + return (TypeSourceInfo **)this->getExtraLocalData(); + } + public: SourceLocation getKWLoc() const { return getLocalData()->KWLoc; } void setKWLoc(SourceLocation Loc) { getLocalData()->KWLoc = Loc; } @@ -1940,12 +1947,26 @@ SourceLocation getRParenLoc() const { return getLocalData()->RParenLoc; } void setRParenLoc(SourceLocation Loc) { getLocalData()->RParenLoc = Loc; } - TypeSourceInfo* getUnderlyingTInfo() const { - return getLocalData()->UnderlyingTInfo; + unsigned getNumArgs() const { return this->getTypePtr()->getNumArgs(); } + + ArrayRef getArgTInfo() const { + return llvm::makeArrayRef(getArgLocArray(), getNumArgs()); } - void setUnderlyingTInfo(TypeSourceInfo *TInfo) { - getLocalData()->UnderlyingTInfo = TInfo; + TypeSourceInfo *getArgInfo(unsigned I) { + assert(I < getNumArgs()); + return getArgLocArray()[I]; + } + + void setArgInfo(unsigned I, TypeSourceInfo *Info) { + assert(I < getNumArgs()); + getArgLocArray()[I] = Info; + } + + void setArgTInfo(ArrayRef ArgInfo) { + assert(ArgInfo.size() == getNumArgs()); + for (unsigned I = 0; I < ArgInfo.size(); ++I) + setArgInfo(I, ArgInfo[I]); } SourceRange getLocalSourceRange() const { @@ -1962,6 +1983,16 @@ } void initializeLocal(ASTContext &Context, SourceLocation Loc); + + unsigned getExtraLocalDataSize() const { + return this->getNumArgs() * sizeof(TypeSourceInfo *); + } + + unsigned getExtraLocalDataAlignment() const { + static_assert(alignof(TransformTraitTypeLoc) >= alignof(TypeSourceInfo *), + "not enough alignment for tail-allocated data"); + return alignof(TypeSourceInfo *); + } }; class DeducedTypeLoc Index: include/clang/AST/TypeNodes.def =================================================================== --- include/clang/AST/TypeNodes.def +++ include/clang/AST/TypeNodes.def @@ -87,7 +87,8 @@ NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TypeOfExpr, Type) NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TypeOf, Type) NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Decltype, Type) -NON_CANONICAL_UNLESS_DEPENDENT_TYPE(UnaryTransform, Type) +NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TransformTrait, Type) + ABSTRACT_TYPE(Tag, Type) TYPE(Record, TagType) TYPE(Enum, TagType) Index: include/clang/ASTMatchers/ASTMatchers.h =================================================================== --- include/clang/ASTMatchers/ASTMatchers.h +++ include/clang/ASTMatchers/ASTMatchers.h @@ -5259,7 +5259,11 @@ /// \endcode /// unaryTransformType() /// matches "__underlying_type(T)" -extern const AstTypeMatcher unaryTransformType; +AST_MATCHER(Type, unaryTransformType) { + if (const auto *T = Node.getAs()) + return T->getNumArgs() == 1; + return false; +} /// \brief Matches record types (e.g. structs, classes). /// Index: include/clang/Basic/DiagnosticCommonKinds.td =================================================================== --- include/clang/Basic/DiagnosticCommonKinds.td +++ include/clang/Basic/DiagnosticCommonKinds.td @@ -108,6 +108,10 @@ "%0 attribute cannot be applied to types">; def err_enum_template : Error<"enumeration cannot be a template">; +// Type traits +def err_type_trait_arity : Error< + "type trait requires %0%select{| or more| or fewer}1 argument%select{|s}2; have " + "%3 argument%s3">; } let CategoryName = "Nullability Issue" in { Index: include/clang/Basic/DiagnosticParseKinds.td =================================================================== --- include/clang/Basic/DiagnosticParseKinds.td +++ include/clang/Basic/DiagnosticParseKinds.td @@ -882,11 +882,6 @@ def err_type_safety_unknown_flag : Error< "invalid comparison flag %0; use 'layout_compatible' or 'must_be_null'">; -// Type traits -def err_type_trait_arity : Error< - "type trait requires %0%select{| or more}1 argument%select{|s}2; have " - "%3 argument%s3">; - // Language specific pragmas // - Generic warnings def warn_pragma_expected_lparen : Warning< Index: include/clang/Basic/Specifiers.h =================================================================== --- include/clang/Basic/Specifiers.h +++ include/clang/Basic/Specifiers.h @@ -46,35 +46,35 @@ TST_unspecified, TST_void, TST_char, - TST_wchar, // C++ wchar_t - TST_char16, // C++11 char16_t - TST_char32, // C++11 char32_t + TST_wchar, // C++ wchar_t + TST_char16, // C++11 char16_t + TST_char32, // C++11 char32_t TST_int, TST_int128, - TST_half, // OpenCL half, ARM NEON __fp16 - TST_Float16, // C11 extension ISO/IEC TS 18661-3 + TST_half, // OpenCL half, ARM NEON __fp16 + TST_Float16, // C11 extension ISO/IEC TS 18661-3 TST_float, TST_double, TST_float128, - TST_bool, // _Bool - TST_decimal32, // _Decimal32 - TST_decimal64, // _Decimal64 - TST_decimal128, // _Decimal128 + TST_bool, // _Bool + TST_decimal32, // _Decimal32 + TST_decimal64, // _Decimal64 + TST_decimal128, // _Decimal128 TST_enum, TST_union, TST_struct, - TST_class, // C++ class type - TST_interface, // C++ (Microsoft-specific) __interface type - TST_typename, // Typedef, C++ class-name or enum name, etc. + TST_class, // C++ class type + TST_interface, // C++ (Microsoft-specific) __interface type + TST_typename, // Typedef, C++ class-name or enum name, etc. TST_typeofType, TST_typeofExpr, - TST_decltype, // C++11 decltype - TST_underlyingType, // __underlying_type for C++11 - TST_auto, // C++11 auto - TST_decltype_auto, // C++1y decltype(auto) - TST_auto_type, // __auto_type extension - TST_unknown_anytype, // __unknown_anytype extension - TST_atomic, // C11 _Atomic + TST_decltype, // C++11 decltype + TST_underlyingType, // __underlying_type for C++11 + TST_auto, // C++11 auto + TST_decltype_auto, // C++1y decltype(auto) + TST_auto_type, // __auto_type extension + TST_unknown_anytype, // __unknown_anytype extension + TST_atomic, // C11 _Atomic #define GENERIC_IMAGE_TYPE(ImgType, Id) TST_##ImgType##_t, // OpenCL image types #include "clang/Basic/OpenCLImageTypes.def" TST_error // erroneous type Index: include/clang/Parse/Parser.h =================================================================== --- include/clang/Parse/Parser.h +++ include/clang/Parse/Parser.h @@ -2407,7 +2407,7 @@ void AnnotateExistingDecltypeSpecifier(const DeclSpec &DS, SourceLocation StartLoc, SourceLocation EndLoc); - void ParseUnderlyingTypeSpecifier(DeclSpec &DS); + void ParseTransformTraitTypeSpecifier(DeclSpec &DS); void ParseAtomicSpecifier(DeclSpec &DS); ExprResult ParseAlignArgument(SourceLocation Start, Index: include/clang/Sema/DeclSpec.h =================================================================== --- include/clang/Sema/DeclSpec.h +++ include/clang/Sema/DeclSpec.h @@ -368,6 +368,8 @@ Expr *ExprRep; }; + SmallVector TypeListRep; + // attributes. ParsedAttributes Attrs; @@ -400,12 +402,14 @@ ObjCDeclSpec *ObjCQualifiers; static bool isTypeRep(TST T) { - return (T == TST_typename || T == TST_typeofType || - T == TST_underlyingType || T == TST_atomic); + return (T == TST_typename || T == TST_typeofType || T == TST_atomic); } static bool isExprRep(TST T) { return (T == TST_typeofExpr || T == TST_decltype); } + static bool isTypeListRep(TST T) { + return (T == TST_underlyingType); + } DeclSpec(const DeclSpec &) = delete; void operator=(const DeclSpec &) = delete; @@ -481,6 +485,7 @@ bool isTypeAltiVecBool() const { return TypeAltiVecBool; } bool isTypeSpecOwned() const { return TypeSpecOwned; } bool isTypeRep() const { return isTypeRep((TST) TypeSpecType); } + bool isTypeListRep() const { return isTypeListRep((TST)TypeSpecType); } bool isTypeSpecPipe() const { return TypeSpecPipe; } ParsedType getRepAsType() const { @@ -495,6 +500,12 @@ assert(isExprRep((TST) TypeSpecType) && "DeclSpec does not store an expr"); return ExprRep; } + ArrayRef getRepAsTypeList() const { + assert(isTypeListRep((TST)TypeSpecType) && + "DeclSpec does not store a type list"); + + return TypeListRep; + } CXXScopeSpec &getTypeSpecScope() { return TypeScope; } const CXXScopeSpec &getTypeSpecScope() const { return TypeScope; } @@ -644,10 +655,12 @@ SourceLocation TagNameLoc, const char *&PrevSpec, unsigned &DiagID, Decl *Rep, bool Owned, const PrintingPolicy &Policy); - bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID, Expr *Rep, const PrintingPolicy &policy); + bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID, ArrayRef Rep, + const PrintingPolicy &policy); bool SetTypeAltiVecVector(bool isAltiVecVector, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID, const PrintingPolicy &Policy); Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -1643,8 +1643,9 @@ /// context, such as when building a type for decltype(auto). QualType BuildDecltypeType(Expr *E, SourceLocation Loc, bool AsUnevaluated = true); - QualType BuildUnaryTransformType(QualType BaseType, - UnaryTransformType::UTTKind UKind, + + QualType BuildTransformTraitType(ArrayRef ArgTypes, + TransformTraitType::TTKind Kind, SourceLocation Loc); //===--------------------------------------------------------------------===// Index: include/clang/Serialization/ASTBitCodes.h =================================================================== --- include/clang/Serialization/ASTBitCodes.h +++ include/clang/Serialization/ASTBitCodes.h @@ -957,133 +957,133 @@ /// AST. Note that DeclCode values share this code space. enum TypeCode { /// \brief An ExtQualType record. - TYPE_EXT_QUAL = 1, + TYPE_EXT_QUAL = 1, /// \brief A ComplexType record. - TYPE_COMPLEX = 3, + TYPE_COMPLEX = 3, /// \brief A PointerType record. - TYPE_POINTER = 4, + TYPE_POINTER = 4, /// \brief A BlockPointerType record. - TYPE_BLOCK_POINTER = 5, + TYPE_BLOCK_POINTER = 5, /// \brief An LValueReferenceType record. - TYPE_LVALUE_REFERENCE = 6, + TYPE_LVALUE_REFERENCE = 6, /// \brief An RValueReferenceType record. - TYPE_RVALUE_REFERENCE = 7, + TYPE_RVALUE_REFERENCE = 7, /// \brief A MemberPointerType record. - TYPE_MEMBER_POINTER = 8, + TYPE_MEMBER_POINTER = 8, /// \brief A ConstantArrayType record. - TYPE_CONSTANT_ARRAY = 9, + TYPE_CONSTANT_ARRAY = 9, /// \brief An IncompleteArrayType record. - TYPE_INCOMPLETE_ARRAY = 10, + TYPE_INCOMPLETE_ARRAY = 10, /// \brief A VariableArrayType record. - TYPE_VARIABLE_ARRAY = 11, + TYPE_VARIABLE_ARRAY = 11, /// \brief A VectorType record. - TYPE_VECTOR = 12, + TYPE_VECTOR = 12, /// \brief An ExtVectorType record. - TYPE_EXT_VECTOR = 13, + TYPE_EXT_VECTOR = 13, /// \brief A FunctionNoProtoType record. - TYPE_FUNCTION_NO_PROTO = 14, + TYPE_FUNCTION_NO_PROTO = 14, /// \brief A FunctionProtoType record. - TYPE_FUNCTION_PROTO = 15, + TYPE_FUNCTION_PROTO = 15, /// \brief A TypedefType record. - TYPE_TYPEDEF = 16, + TYPE_TYPEDEF = 16, /// \brief A TypeOfExprType record. - TYPE_TYPEOF_EXPR = 17, + TYPE_TYPEOF_EXPR = 17, /// \brief A TypeOfType record. - TYPE_TYPEOF = 18, + TYPE_TYPEOF = 18, /// \brief A RecordType record. - TYPE_RECORD = 19, + TYPE_RECORD = 19, /// \brief An EnumType record. - TYPE_ENUM = 20, + TYPE_ENUM = 20, /// \brief An ObjCInterfaceType record. - TYPE_OBJC_INTERFACE = 21, + TYPE_OBJC_INTERFACE = 21, /// \brief An ObjCObjectPointerType record. - TYPE_OBJC_OBJECT_POINTER = 22, + TYPE_OBJC_OBJECT_POINTER = 22, /// \brief a DecltypeType record. - TYPE_DECLTYPE = 23, + TYPE_DECLTYPE = 23, /// \brief An ElaboratedType record. - TYPE_ELABORATED = 24, + TYPE_ELABORATED = 24, /// \brief A SubstTemplateTypeParmType record. TYPE_SUBST_TEMPLATE_TYPE_PARM = 25, /// \brief An UnresolvedUsingType record. - TYPE_UNRESOLVED_USING = 26, + TYPE_UNRESOLVED_USING = 26, /// \brief An InjectedClassNameType record. - TYPE_INJECTED_CLASS_NAME = 27, + TYPE_INJECTED_CLASS_NAME = 27, /// \brief An ObjCObjectType record. - TYPE_OBJC_OBJECT = 28, + TYPE_OBJC_OBJECT = 28, /// \brief An TemplateTypeParmType record. - TYPE_TEMPLATE_TYPE_PARM = 29, + TYPE_TEMPLATE_TYPE_PARM = 29, /// \brief An TemplateSpecializationType record. - TYPE_TEMPLATE_SPECIALIZATION = 30, + TYPE_TEMPLATE_SPECIALIZATION = 30, /// \brief A DependentNameType record. - TYPE_DEPENDENT_NAME = 31, + TYPE_DEPENDENT_NAME = 31, /// \brief A DependentTemplateSpecializationType record. TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION = 32, /// \brief A DependentSizedArrayType record. - TYPE_DEPENDENT_SIZED_ARRAY = 33, + TYPE_DEPENDENT_SIZED_ARRAY = 33, /// \brief A ParenType record. - TYPE_PAREN = 34, + TYPE_PAREN = 34, /// \brief A PackExpansionType record. - TYPE_PACK_EXPANSION = 35, + TYPE_PACK_EXPANSION = 35, /// \brief An AttributedType record. - TYPE_ATTRIBUTED = 36, + TYPE_ATTRIBUTED = 36, /// \brief A SubstTemplateTypeParmPackType record. TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK = 37, /// \brief A AutoType record. - TYPE_AUTO = 38, + TYPE_AUTO = 38, - /// \brief A UnaryTransformType record. - TYPE_UNARY_TRANSFORM = 39, + /// \brief A TransformTraitType record. + TYPE_TRANSFORM_TRAIT = 39, /// \brief An AtomicType record. - TYPE_ATOMIC = 40, + TYPE_ATOMIC = 40, /// \brief A DecayedType record. - TYPE_DECAYED = 41, + TYPE_DECAYED = 41, /// \brief An AdjustedType record. - TYPE_ADJUSTED = 42, + TYPE_ADJUSTED = 42, /// \brief A PipeType record. - TYPE_PIPE = 43, + TYPE_PIPE = 43, /// \brief An ObjCTypeParamType record. - TYPE_OBJC_TYPE_PARAM = 44, + TYPE_OBJC_TYPE_PARAM = 44, /// \brief A DeducedTemplateSpecializationType record. TYPE_DEDUCED_TEMPLATE_SPECIALIZATION = 45, Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -2984,7 +2984,7 @@ case Type::TypeOfExpr: case Type::TypeOf: case Type::Decltype: - case Type::UnaryTransform: + case Type::TransformTrait: case Type::DependentName: case Type::InjectedClassName: case Type::TemplateSpecialization: @@ -4639,38 +4639,46 @@ return QualType(dt, 0); } -/// getUnaryTransformationType - We don't unique these, since the memory +/// getTransformTraitType - We don't unique these, since the memory /// savings are minimal and these are rare. -QualType ASTContext::getUnaryTransformType(QualType BaseType, - QualType UnderlyingType, - UnaryTransformType::UTTKind Kind) - const { - UnaryTransformType *ut = nullptr; - - if (BaseType->isDependentType()) { +QualType +ASTContext::getTransformTraitType(ArrayRef ArgTypes, + QualType TransformedType, + TransformTraitType::TTKind Kind) const { + TransformTraitType *ut = nullptr; + + bool IsDependent = + llvm::any_of(ArgTypes, [](QualType T) { return T->isDependentType(); }); + + if (IsDependent) { + assert(TransformedType->isDependentType() && + "non-dependent transformed type with dependent argument types"); + SmallVector CanonArgs; + CanonArgs.reserve(ArgTypes.size()); + for (auto Ty : ArgTypes) + CanonArgs.push_back(getCanonicalType(Ty)); // Look in the folding set for an existing type. llvm::FoldingSetNodeID ID; - DependentUnaryTransformType::Profile(ID, getCanonicalType(BaseType), Kind); + DependentTransformTraitType::Profile(ID, CanonArgs, Kind); void *InsertPos = nullptr; - DependentUnaryTransformType *Canon - = DependentUnaryTransformTypes.FindNodeOrInsertPos(ID, InsertPos); + DependentTransformTraitType *Canon = + DependentTransformTraitTypes.FindNodeOrInsertPos(ID, InsertPos); if (!Canon) { - // Build a new, canonical __underlying_type(type) type. + // Build a new, canonical transformation trait type. Canon = new (*this, TypeAlignment) - DependentUnaryTransformType(*this, getCanonicalType(BaseType), - Kind); - DependentUnaryTransformTypes.InsertNode(Canon, InsertPos); + DependentTransformTraitType(*this, CanonArgs, Kind); + DependentTransformTraitTypes.InsertNode(Canon, InsertPos); } - ut = new (*this, TypeAlignment) UnaryTransformType (BaseType, - QualType(), Kind, - QualType(Canon, 0)); + ut = new (*this, TypeAlignment) + TransformTraitType(ArgTypes, QualType(), Kind, QualType(Canon, 0)); } else { - QualType CanonType = getCanonicalType(UnderlyingType); - ut = new (*this, TypeAlignment) UnaryTransformType (BaseType, - UnderlyingType, Kind, - CanonType); + assert(!TransformedType->isDependentType() && + "dependent transformed type with non-dependent argument types"); + QualType CanonType = getCanonicalType(TransformedType); + ut = new (*this, TypeAlignment) + TransformTraitType(ArgTypes, TransformedType, Kind, CanonType); } Types.push_back(ut); return QualType(ut, 0); Index: lib/AST/ASTDumper.cpp =================================================================== --- lib/AST/ASTDumper.cpp +++ lib/AST/ASTDumper.cpp @@ -362,13 +362,14 @@ void VisitDecltypeType(const DecltypeType *T) { dumpStmt(T->getUnderlyingExpr()); } - void VisitUnaryTransformType(const UnaryTransformType *T) { - switch (T->getUTTKind()) { - case UnaryTransformType::EnumUnderlyingType: + void VisitTransformTraitType(const TransformTraitType *T) { + switch (T->getTTKind()) { + case TransformTraitType::EnumUnderlyingType: OS << " underlying_type"; break; } - dumpTypeAsChild(T->getBaseType()); + for (auto Ty : T->getArgs()) + dumpTypeAsChild(Ty); } void VisitTagType(const TagType *T) { dumpDeclRef(T->getDecl()); @@ -2213,14 +2214,14 @@ } void ASTDumper::VisitUnaryOperator(const UnaryOperator *Node) { - VisitExpr(Node); - OS << " " << (Node->isPostfix() ? "postfix" : "prefix") - << " '" << UnaryOperator::getOpcodeStr(Node->getOpcode()) << "'"; - if (!Node->canOverflow()) - OS << " cannot overflow"; -} - -void ASTDumper::VisitUnaryExprOrTypeTraitExpr( + VisitExpr(Node); + OS << " " << (Node->isPostfix() ? "postfix" : "prefix") << " '" + << UnaryOperator::getOpcodeStr(Node->getOpcode()) << "'"; + if (!Node->canOverflow()) + OS << " cannot overflow"; +} + +void ASTDumper::VisitUnaryExprOrTypeTraitExpr( const UnaryExprOrTypeTraitExpr *Node) { VisitExpr(Node); switch(Node->getKind()) { Index: lib/AST/ASTImporter.cpp =================================================================== --- lib/AST/ASTImporter.cpp +++ lib/AST/ASTImporter.cpp @@ -64,7 +64,7 @@ // FIXME: DependentTypeOfExprType QualType VisitTypeOfType(const TypeOfType *T); QualType VisitDecltypeType(const DecltypeType *T); - QualType VisitUnaryTransformType(const UnaryTransformType *T); + QualType VisitTransformTraitType(const TransformTraitType *T); QualType VisitAutoType(const AutoType *T); QualType VisitInjectedClassNameType(const InjectedClassNameType *T); // FIXME: DependentDecltypeType @@ -712,15 +712,21 @@ return Importer.getToContext().getDecltypeType(ToExpr, UnderlyingType); } -QualType ASTNodeImporter::VisitUnaryTransformType(const UnaryTransformType *T) { - QualType ToBaseType = Importer.Import(T->getBaseType()); - QualType ToUnderlyingType = Importer.Import(T->getUnderlyingType()); - if (ToBaseType.isNull() || ToUnderlyingType.isNull()) + +QualType ASTNodeImporter::VisitTransformTraitType(const TransformTraitType *T) { + SmallVector ToArgTypes; + for (auto Ty : T->getArgs()) { + QualType ToTy = Importer.Import(Ty); + if (ToTy.isNull()) + return QualType(); + ToArgTypes.push_back(ToTy); + } + QualType ToTransformedType = Importer.Import(T->getTransformedType()); + if (ToTransformedType.isNull()) return QualType(); - return Importer.getToContext().getUnaryTransformType(ToBaseType, - ToUnderlyingType, - T->getUTTKind()); + return Importer.getToContext().getTransformTraitType( + ToArgTypes, ToTransformedType, T->getTTKind()); } QualType ASTNodeImporter::VisitAutoType(const AutoType *T) { Index: lib/AST/ASTStructuralEquivalence.cpp =================================================================== --- lib/AST/ASTStructuralEquivalence.cpp +++ lib/AST/ASTStructuralEquivalence.cpp @@ -498,13 +498,20 @@ return false; break; - case Type::UnaryTransform: - if (!IsStructurallyEquivalent( - Context, cast(T1)->getUnderlyingType(), - cast(T1)->getUnderlyingType())) + case Type::TransformTrait: { + const TransformTraitType *TT1 = cast(T1); + const TransformTraitType *TT2 = cast(T2); + if (TT1->getNumArgs() != TT2->getNumArgs()) + return false; + for (unsigned I = 0; I < TT1->getNumArgs(); ++I) { + if (!IsStructurallyEquivalent(Context, TT1->getArg(I), TT2->getArg(I))) + return false; + } + if (!IsStructurallyEquivalent(Context, TT1->getTransformedType(), + TT2->getTransformedType())) return false; break; - + } case Type::Decltype: if (!IsStructurallyEquivalent(Context, cast(T1)->getUnderlyingExpr(), Index: lib/AST/ItaniumMangle.cpp =================================================================== --- lib/AST/ItaniumMangle.cpp +++ lib/AST/ItaniumMangle.cpp @@ -1964,7 +1964,7 @@ case Type::TypeOf: case Type::Decltype: case Type::TemplateTypeParm: - case Type::UnaryTransform: + case Type::TransformTrait: case Type::SubstTemplateTypeParm: unresolvedType: // Some callers want a prefix before the mangled type. @@ -3234,20 +3234,21 @@ Out << 'E'; } -void CXXNameMangler::mangleType(const UnaryTransformType *T) { +void CXXNameMangler::mangleType(const TransformTraitType *T) { // 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'; - - switch (T->getUTTKind()) { - case UnaryTransformType::EnumUnderlyingType: - Out << "3eut"; - break; + + switch (T->getTTKind()) { + case TransformTraitType::EnumUnderlyingType: + Out << "3eut"; + break; } } - mangleType(T->getBaseType()); + for (auto Ty : T->getArgs()) + mangleType(Ty); } void CXXNameMangler::mangleType(const AutoType *T) { Index: lib/AST/MicrosoftMangle.cpp =================================================================== --- lib/AST/MicrosoftMangle.cpp +++ lib/AST/MicrosoftMangle.cpp @@ -2617,13 +2617,12 @@ << Range; } -void MicrosoftCXXNameMangler::mangleType(const UnaryTransformType *T, +void MicrosoftCXXNameMangler::mangleType(const TransformTraitType *T, Qualifiers, SourceRange Range) { DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle this unary transform type yet"); - Diags.Report(Range.getBegin(), DiagID) - << Range; + unsigned DiagID = Diags.getCustomDiagID( + DiagnosticsEngine::Error, "cannot mangle this transform type yet"); + Diags.Report(Range.getBegin(), DiagID) << Range; } void MicrosoftCXXNameMangler::mangleType(const AutoType *T, Qualifiers, Index: lib/AST/Type.cpp =================================================================== --- lib/AST/Type.cpp +++ lib/AST/Type.cpp @@ -967,10 +967,34 @@ TRIVIAL_TYPE_CLASS(TypeOfExpr) TRIVIAL_TYPE_CLASS(TypeOf) TRIVIAL_TYPE_CLASS(Decltype) - TRIVIAL_TYPE_CLASS(UnaryTransform) TRIVIAL_TYPE_CLASS(Record) TRIVIAL_TYPE_CLASS(Enum) + QualType VisitTransformTraitType(const TransformTraitType *T) { + // Transform type arguments. + bool typeArgChanged = false; + SmallVector typeArgs; + for (auto typeArg : T->getArgs()) { + QualType newTypeArg = recurse(typeArg); + if (newTypeArg.isNull()) + return {}; + + if (newTypeArg.getAsOpaquePtr() != typeArg.getAsOpaquePtr()) + typeArgChanged = true; + + typeArgs.push_back(newTypeArg); + } + QualType TransformedType = recurse(T->getTransformedType()); + if (TransformedType.isNull()) + return {}; + if (TransformedType.getAsOpaquePtr() == + T->getTransformedType().getAsOpaquePtr() && + !typeArgChanged) + return QualType(T, 0); + + return Ctx.getTransformTraitType(typeArgs, TransformedType, T->getTTKind()); + } + // FIXME: Non-trivial to implement, but important for C++ TRIVIAL_TYPE_CLASS(Elaborated) @@ -3042,20 +3066,27 @@ E->Profile(ID, Context, true); } -UnaryTransformType::UnaryTransformType(QualType BaseType, - QualType UnderlyingType, - UTTKind UKind, +TransformTraitType::TransformTraitType(ArrayRef ArgTys, + QualType TransformedTy, TTKind TKind, QualType CanonicalType) - : Type(UnaryTransform, CanonicalType, BaseType->isDependentType(), - BaseType->isInstantiationDependentType(), - BaseType->isVariablyModifiedType(), - BaseType->containsUnexpandedParameterPack()), - BaseType(BaseType), UnderlyingType(UnderlyingType), UKind(UKind) {} + : Type(TransformTrait, CanonicalType, false, false, false, false), + ArgTypes(ArgTys.begin(), ArgTys.end()), TransformedType(TransformedTy) { + TransformTraitTypeBits.TTKind = TKind; + for (QualType T : ArgTypes) { + if (T->isDependentType()) + this->setDependent(true); + if (T->isInstantiationDependentType()) + this->setInstantiationDependent(true); + if (T->isVariablyModifiedType()) + this->setVariablyModified(true); + if (T->containsUnexpandedParameterPack()) + this->setContainsUnexpandedParameterPack(true); + } +} -DependentUnaryTransformType::DependentUnaryTransformType(const ASTContext &C, - QualType BaseType, - UTTKind UKind) - : UnaryTransformType(BaseType, C.DependentTy, UKind, QualType()) {} +DependentTransformTraitType::DependentTransformTraitType( + const ASTContext &C, ArrayRef ArgTys, TTKind TKind) + : TransformTraitType(ArgTys, C.DependentTy, TKind, QualType()) {} TagType::TagType(TypeClass TC, const TagDecl *D, QualType can) : Type(TC, can, D->isDependentType(), @@ -3676,7 +3707,7 @@ case Type::TypeOfExpr: case Type::TypeOf: case Type::Decltype: - case Type::UnaryTransform: + case Type::TransformTrait: case Type::TemplateTypeParm: case Type::SubstTemplateTypeParmPack: case Type::DependentName: Index: lib/AST/TypeLoc.cpp =================================================================== --- lib/AST/TypeLoc.cpp +++ lib/AST/TypeLoc.cpp @@ -444,13 +444,15 @@ getUnderlyingType(), Loc); } -void UnaryTransformTypeLoc::initializeLocal(ASTContext &Context, - SourceLocation Loc) { - setKWLoc(Loc); - setRParenLoc(Loc); - setLParenLoc(Loc); - this->setUnderlyingTInfo( - Context.getTrivialTypeSourceInfo(getTypePtr()->getBaseType(), Loc)); +void TransformTraitTypeLoc::initializeLocal(ASTContext &Context, + SourceLocation Loc) { + setKWLoc(Loc); + setRParenLoc(Loc); + setLParenLoc(Loc); + for (unsigned I = 0; I < getTypePtr()->getNumArgs(); ++I) { + this->setArgInfo( + I, Context.getTrivialTypeSourceInfo(getTypePtr()->getArg(I), Loc)); + } } void ElaboratedTypeLoc::initializeLocal(ASTContext &Context, Index: lib/AST/TypePrinter.cpp =================================================================== --- lib/AST/TypePrinter.cpp +++ lib/AST/TypePrinter.cpp @@ -184,7 +184,7 @@ case Type::TypeOfExpr: case Type::TypeOf: case Type::Decltype: - case Type::UnaryTransform: + case Type::TransformTrait: case Type::Record: case Type::Enum: case Type::Elaborated: @@ -879,33 +879,38 @@ OS << ')'; spaceBeforePlaceHolder(OS); } -void TypePrinter::printDecltypeAfter(const DecltypeType *T, raw_ostream &OS) { } +void TypePrinter::printDecltypeAfter(const DecltypeType *T, raw_ostream &OS) {} -void TypePrinter::printUnaryTransformBefore(const UnaryTransformType *T, +void TypePrinter::printTransformTraitBefore(const TransformTraitType *T, raw_ostream &OS) { IncludeStrongLifetimeRAII Strong(Policy); - switch (T->getUTTKind()) { - case UnaryTransformType::EnumUnderlyingType: - OS << "__underlying_type("; - print(T->getBaseType(), OS, StringRef()); - OS << ')'; - spaceBeforePlaceHolder(OS); - return; + switch (T->getTTKind()) { + case TransformTraitType::EnumUnderlyingType: + OS << "__underlying_type("; + break; } - - printBefore(T->getBaseType(), OS); + for (unsigned I = 0; I != T->getNumArgs(); ++I) { + print(T->getArg(I), OS, StringRef()); + if ((I + 1) != T->getNumArgs()) + OS << ", "; + } + OS << ')'; + spaceBeforePlaceHolder(OS); + return; + llvm_unreachable("transformation trait not handled"); } -void TypePrinter::printUnaryTransformAfter(const UnaryTransformType *T, + +void TypePrinter::printTransformTraitAfter(const TransformTraitType *T, raw_ostream &OS) { IncludeStrongLifetimeRAII Strong(Policy); - switch (T->getUTTKind()) { - case UnaryTransformType::EnumUnderlyingType: - return; + switch (T->getTTKind()) { + case TransformTraitType::EnumUnderlyingType: + return; } - printAfter(T->getBaseType(), OS); + llvm_unreachable("transformation trait not handled"); } void TypePrinter::printAutoBefore(const AutoType *T, raw_ostream &OS) { Index: lib/ASTMatchers/ASTMatchersInternal.cpp =================================================================== --- lib/ASTMatchers/ASTMatchersInternal.cpp +++ lib/ASTMatchers/ASTMatchersInternal.cpp @@ -809,7 +809,7 @@ const AstTypeMatcher typedefType; const AstTypeMatcher enumType; const AstTypeMatcher templateSpecializationType; -const AstTypeMatcher unaryTransformType; +const AstTypeMatcher transformTraingType; const AstTypeMatcher recordType; const AstTypeMatcher tagType; const AstTypeMatcher elaboratedType; Index: lib/CodeGen/CGDebugInfo.cpp =================================================================== --- lib/CodeGen/CGDebugInfo.cpp +++ lib/CodeGen/CGDebugInfo.cpp @@ -2585,8 +2585,8 @@ case Type::Decltype: T = cast(T)->getUnderlyingType(); break; - case Type::UnaryTransform: - T = cast(T)->getUnderlyingType(); + case Type::TransformTrait: + T = cast(T)->getTransformedType(); break; case Type::Attributed: T = cast(T)->getEquivalentType(); @@ -2780,7 +2780,7 @@ case Type::TypeOfExpr: case Type::TypeOf: case Type::Decltype: - case Type::UnaryTransform: + case Type::TransformTrait: case Type::PackExpansion: break; } Index: lib/CodeGen/CodeGenFunction.cpp =================================================================== --- lib/CodeGen/CodeGenFunction.cpp +++ lib/CodeGen/CodeGenFunction.cpp @@ -2093,7 +2093,7 @@ case Type::Paren: case Type::TypeOf: - case Type::UnaryTransform: + case Type::TransformTrait: case Type::Attributed: case Type::SubstTemplateTypeParm: case Type::PackExpansion: Index: lib/Lex/PPMacroExpansion.cpp =================================================================== --- lib/Lex/PPMacroExpansion.cpp +++ lib/Lex/PPMacroExpansion.cpp @@ -1243,7 +1243,6 @@ //.Case("cxx_runtime_arrays", LangOpts.CPlusPlusTSArrays) //.Case("cxx_concepts", LangOpts.CPlusPlusTSConcepts) // FIXME: Should this be __has_feature or __has_extension? - //.Case("raw_invocation_type", LangOpts.CPlusPlus) // Type traits // N.B. Additional type traits should not be added to the following list. // Instead, they should be detected by has_extension. Index: lib/Parse/ParseDecl.cpp =================================================================== --- lib/Parse/ParseDecl.cpp +++ lib/Parse/ParseDecl.cpp @@ -3722,7 +3722,7 @@ continue; case tok::kw___underlying_type: - ParseUnderlyingTypeSpecifier(DS); + ParseTransformTraitTypeSpecifier(DS); continue; case tok::kw__Atomic: Index: lib/Parse/ParseDeclCXX.cpp =================================================================== --- lib/Parse/ParseDeclCXX.cpp +++ lib/Parse/ParseDeclCXX.cpp @@ -1020,35 +1020,86 @@ PP.AnnotateCachedTokens(Tok); } -void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) { - assert(Tok.is(tok::kw___underlying_type) && - "Not an underlying type specifier"); +struct TransformTraitInfo { + unsigned MinArity, MaxArity; + DeclSpec::TST TypeSpecType; +}; + +static TransformTraitInfo GetTraitInfo(tok::TokenKind Kind) { + switch (Kind) { + case tok::kw___underlying_type: + return {1, 1, DeclSpec::TST_underlyingType}; + default: + llvm_unreachable("Not a transformation trait type specifier"); + } +} + +void Parser::ParseTransformTraitTypeSpecifier(DeclSpec &DS) { + TransformTraitInfo Info = GetTraitInfo(Tok.getKind()); SourceLocation StartLoc = ConsumeToken(); - BalancedDelimiterTracker T(*this, tok::l_paren); - if (T.expectAndConsume(diag::err_expected_lparen_after, - "__underlying_type", tok::r_paren)) { + BalancedDelimiterTracker Parens(*this, tok::l_paren); + if (Parens.expectAndConsume()) return; - } - TypeResult Result = ParseTypeName(); - if (Result.isInvalid()) { - SkipUntil(tok::r_paren, StopAtSemi); - return; + SmallVector Args; + if (Tok.isNot(tok::r_paren)) { + do { + // Parse the next type. + TypeResult Ty = ParseTypeName(); + if (Ty.isInvalid()) { + Parens.skipToEnd(); + return; + } + + // Parse the ellipsis, if present. + if (Tok.is(tok::ellipsis)) { + Ty = Actions.ActOnPackExpansion(Ty.get(), ConsumeToken()); + if (Ty.isInvalid()) { + Parens.skipToEnd(); + return; + } + } + + // Add this type to the list of arguments. + Args.push_back(Ty.get()); + } while (TryConsumeToken(tok::comma)); } + if (Parens.consumeClose()) + return; - // Match the ')' - T.consumeClose(); - if (T.getCloseLocation().isInvalid()) + SourceLocation EndLoc = Parens.getCloseLocation(); + + struct DiagInfo { + unsigned ReqNumArgs; + unsigned SelectOne; + }; + auto DiagSelect = [&]() -> Optional { + if (Info.MinArity && Info.MinArity == Info.MaxArity && + Info.MinArity != Args.size()) + return DiagInfo{Info.MinArity, 0}; + if (Info.MinArity && Args.size() < Info.MinArity) + return DiagInfo{Info.MinArity, 1}; + if (Info.MaxArity && Args.size() > Info.MaxArity) + return DiagInfo{Info.MaxArity, 2}; + return {}; + }(); + + if (DiagSelect.hasValue()) { + auto &Info = DiagSelect.getValue(); + Diag(EndLoc, diag::err_type_trait_arity) + << Info.ReqNumArgs << Info.SelectOne << (Info.ReqNumArgs != 1) + << (int)Args.size() << SourceRange(StartLoc); return; + } + // TST const char *PrevSpec = nullptr; unsigned DiagID; - if (DS.SetTypeSpecType(DeclSpec::TST_underlyingType, StartLoc, PrevSpec, - DiagID, Result.get(), + if (DS.SetTypeSpecType(Info.TypeSpecType, StartLoc, PrevSpec, DiagID, Args, Actions.getASTContext().getPrintingPolicy())) Diag(StartLoc, DiagID) << PrevSpec; - DS.setTypeofParensRange(T.getRange()); + DS.setTypeofParensRange(Parens.getRange()); } /// ParseBaseTypeSpecifier - Parse a C++ base-type-specifier which is either a Index: lib/Sema/DeclSpec.cpp =================================================================== --- lib/Sema/DeclSpec.cpp +++ lib/Sema/DeclSpec.cpp @@ -367,6 +367,8 @@ return false; case TST_underlyingType: + return false; + case TST_typename: case TST_typeofType: { QualType QT = DS.getRepAsType().get(); @@ -689,6 +691,24 @@ return false; } +bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID, ArrayRef Rep, + const PrintingPolicy &Policy) { + assert(isTypeListRep(T) && "T does not store a type"); + + if (TypeSpecType != TST_unspecified) { + PrevSpec = DeclSpec::getSpecifierName((TST)TypeSpecType, Policy); + DiagID = diag::err_invalid_decl_spec_combination; + return true; + } + TypeSpecType = T; + TypeListRep = SmallVector(Rep.begin(), Rep.end()); + TSTLoc = Loc; + TSTNameLoc = Loc; + TypeSpecOwned = false; + return false; +} + bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID, Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -3901,7 +3901,7 @@ break; case Type::Paren: case Type::TypeOf: - case Type::UnaryTransform: + case Type::TransformTrait: case Type::Attributed: case Type::SubstTemplateTypeParm: case Type::PackExpansion: Index: lib/Sema/SemaTemplate.cpp =================================================================== --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -982,14 +982,14 @@ // Check that we have valid decl-specifiers specified. auto CheckValidDeclSpecifiers = [this, &D] { // C++ [temp.param] - // p1 - // template-parameter: - // ... - // parameter-declaration - // p2 + // p1 + // template-parameter: + // ... + // parameter-declaration + // p2 // ... A storage class shall not be specified in a template-parameter // declaration. - // [dcl.typedef]p1: + // [dcl.typedef]p1: // The typedef specifier [...] shall not be used in the decl-specifier-seq // of a parameter-declaration const DeclSpec &DS = D.getDeclSpec(); @@ -5291,8 +5291,8 @@ return false; } -bool UnnamedLocalNoLinkageFinder::VisitUnaryTransformType( - const UnaryTransformType*) { +bool UnnamedLocalNoLinkageFinder::VisitTransformTraitType( + const TransformTraitType *) { return false; } Index: lib/Sema/SemaTemplateDeduction.cpp =================================================================== --- lib/Sema/SemaTemplateDeduction.cpp +++ lib/Sema/SemaTemplateDeduction.cpp @@ -1945,7 +1945,7 @@ case Type::DependentName: case Type::UnresolvedUsing: case Type::Decltype: - case Type::UnaryTransform: + case Type::TransformTrait: case Type::Auto: case Type::DeducedTemplateSpecialization: case Type::DependentTemplateSpecialization: @@ -5357,13 +5357,18 @@ OnlyDeduced, Depth, Used); break; - case Type::UnaryTransform: - if (!OnlyDeduced) - MarkUsedTemplateParameters(Ctx, - cast(T)->getUnderlyingType(), - OnlyDeduced, Depth, Used); + case Type::TransformTrait: { + const TransformTraitType *TT = cast(T); + if (!OnlyDeduced) { + // FIXME(EricWF): Do we mark the input args as used unconditionally? + for (auto Ty : TT->getArgs()) { + MarkUsedTemplateParameters(Ctx, Ty, OnlyDeduced, Depth, Used); + } + MarkUsedTemplateParameters(Ctx, TT->getTransformedType(), OnlyDeduced, + Depth, Used); + } break; - + } case Type::PackExpansion: MarkUsedTemplateParameters(Ctx, cast(T)->getPattern(), Index: lib/Sema/SemaTemplateVariadic.cpp =================================================================== --- lib/Sema/SemaTemplateVariadic.cpp +++ lib/Sema/SemaTemplateVariadic.cpp @@ -803,14 +803,23 @@ switch (DS.getTypeSpecType()) { case TST_typename: case TST_typeofType: - case TST_underlyingType: case TST_atomic: { QualType T = DS.getRepAsType().get(); if (!T.isNull() && T->containsUnexpandedParameterPack()) return true; break; } - + + case TST_underlyingType: { + ArrayRef Args = DS.getRepAsTypeList(); + for (auto PT : Args) { + QualType T = PT.get(); + if (!T.isNull() && T->containsUnexpandedParameterPack()) + return true; + } + break; + } + case TST_typeofExpr: case TST_decltype: if (DS.getRepAsExpr() && Index: lib/Sema/SemaType.cpp =================================================================== --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -1491,18 +1491,31 @@ } break; } - case DeclSpec::TST_underlyingType: - Result = S.GetTypeFromParser(DS.getRepAsType()); - assert(!Result.isNull() && "Didn't get a type for __underlying_type?"); - Result = S.BuildUnaryTransformType(Result, - UnaryTransformType::EnumUnderlyingType, - DS.getTypeSpecTypeLoc()); + case DeclSpec::TST_underlyingType: { + ArrayRef ParsedArgs = DS.getRepAsTypeList(); + SmallVector Args; + Args.reserve(ParsedArgs.size()); + for (auto PT : ParsedArgs) { + QualType NewArg = S.GetTypeFromParser(PT); + assert(!NewArg.isNull()); + Args.push_back(NewArg); + } + TransformTraitType::TTKind TKind; + switch (DS.getTypeSpecType()) { + case DeclSpec::TST_underlyingType: + TKind = TransformTraitType::EnumUnderlyingType; + break; + default: + llvm_unreachable("unhandled case"); + } + + Result = S.BuildTransformTraitType(Args, TKind, DS.getTypeSpecTypeLoc()); if (Result.isNull()) { Result = Context.IntTy; declarator.setInvalidType(true); } break; - + } case DeclSpec::TST_auto: Result = Context.getAutoType(QualType(), AutoTypeKeyword::Auto, false); break; @@ -5323,15 +5336,18 @@ Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo); TL.setUnderlyingTInfo(TInfo); } - void VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) { - // FIXME: This holds only because we only have one unary transform. + void VisitTransformTraitTypeLoc(TransformTraitTypeLoc TL) { assert(DS.getTypeSpecType() == DeclSpec::TST_underlyingType); TL.setKWLoc(DS.getTypeSpecTypeLoc()); TL.setParensRange(DS.getTypeofParensRange()); - assert(DS.getRepAsType()); - TypeSourceInfo *TInfo = nullptr; - Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo); - TL.setUnderlyingTInfo(TInfo); + ArrayRef ParsedArgs = DS.getRepAsTypeList(); + SmallVector ArgInfo; + for (auto PT : ParsedArgs) { + TypeSourceInfo *TInfo = nullptr; + Sema::GetTypeFromParser(PT, &TInfo); + ArgInfo.push_back(TInfo); + } + TL.setArgTInfo(ArgInfo); } void VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { // By default, use the source location of the type specifier. @@ -7982,39 +7998,78 @@ return Context.getDecltypeType(E, getDecltypeForExpr(*this, E)); } -QualType Sema::BuildUnaryTransformType(QualType BaseType, - UnaryTransformType::UTTKind UKind, +static bool diagnoseTransformTraitArity(Sema &S, + TransformTraitType::TTKind Kind, + SourceLocation Loc, unsigned NumArgs) { + unsigned MinArity, MaxArity; + switch (Kind) { + case TransformTraitType::EnumUnderlyingType: + MinArity = MaxArity = 1; + break; + } + struct DiagInfo { + unsigned ReqNumArgs; + unsigned SelectOne; + }; + auto DiagSelect = [&]() -> Optional { + if (MinArity && MinArity == MaxArity && MinArity != NumArgs) + return DiagInfo{MinArity, 0}; + if (MinArity && NumArgs < MinArity) + return DiagInfo{MinArity, 1}; + if (MaxArity && NumArgs > MaxArity) + return DiagInfo{MinArity, 2}; + return {}; + }(); + + if (DiagSelect.hasValue()) { + auto &Info = DiagSelect.getValue(); + S.Diag(Loc, diag::err_type_trait_arity) + << Info.ReqNumArgs << Info.SelectOne << (Info.ReqNumArgs != 1) + << (int)NumArgs << SourceRange(Loc); + return true; + } + return false; +} + +QualType Sema::BuildTransformTraitType(ArrayRef ArgTypes, + TransformTraitType::TTKind TKind, SourceLocation Loc) { - switch (UKind) { - case UnaryTransformType::EnumUnderlyingType: + if (diagnoseTransformTraitArity(*this, TKind, Loc, ArgTypes.size())) + return QualType(); + switch (TKind) { + case TransformTraitType::EnumUnderlyingType: { + assert(ArgTypes.size() == 1 && + "underlying_type takes only a single argument"); + QualType BaseType = ArgTypes[0]; 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(); - } + } + 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(); + } - EnumDecl *ED = BaseType->getAs()->getDecl(); - assert(ED && "EnumType has no EnumDecl"); + EnumDecl *ED = BaseType->getAs()->getDecl(); + assert(ED && "EnumType has no EnumDecl"); - DiagnoseUseOfDecl(ED, Loc); + DiagnoseUseOfDecl(ED, Loc); - Underlying = ED->getIntegerType(); - assert(!Underlying.isNull()); - } - return Context.getUnaryTransformType(BaseType, Underlying, - UnaryTransformType::EnumUnderlyingType); + Underlying = ED->getIntegerType(); + assert(!Underlying.isNull()); } + return Context.getTransformTraitType( + BaseType, Underlying, TransformTraitType::EnumUnderlyingType); } - llvm_unreachable("unknown unary transform type"); + } + + llvm_unreachable("unknown transform type"); } QualType Sema::BuildAtomicType(QualType T, SourceLocation Loc) { Index: lib/Sema/TreeTransform.h =================================================================== --- lib/Sema/TreeTransform.h +++ lib/Sema/TreeTransform.h @@ -622,6 +622,10 @@ TypeLocBuilder &TLB, DependentTemplateSpecializationTypeLoc TL, NestedNameSpecifierLoc QualifierLoc); + bool TransformTypeSourceListAndExpandPacks( + ArrayRef InArgs, bool &ArgChanged, + SmallVectorImpl &Args); + /// \brief Transforms the parameters of a function type into the /// given vectors. /// @@ -888,9 +892,9 @@ /// By default, builds a new TypeOfType with the given underlying type. QualType RebuildTypeOfType(QualType Underlying); - /// \brief Build a new unary transform type. - QualType RebuildUnaryTransformType(QualType BaseType, - UnaryTransformType::UTTKind UKind, + /// \brief Build a new transform trait type. + QualType RebuildTransformTraitType(ArrayRef ArgTypes, + TransformTraitType::TTKind TKind, SourceLocation Loc); /// \brief Build a new C++11 decltype type. @@ -5520,30 +5524,38 @@ return Result; } -template -QualType TreeTransform::TransformUnaryTransformType( - TypeLocBuilder &TLB, - UnaryTransformTypeLoc TL) { +template +QualType +TreeTransform::TransformTransformTraitType(TypeLocBuilder &TLB, + TransformTraitTypeLoc TL) { + bool AnyChanged = false; + SmallVector NewTypeArgInfos; + if (getDerived().TransformTypeSourceListAndExpandPacks( + TL.getArgTInfo(), AnyChanged, NewTypeArgInfos)) + return QualType(); + QualType Result = TL.getType(); - if (Result->isDependentType()) { - const UnaryTransformType *T = TL.getTypePtr(); - QualType NewBase = - getDerived().TransformType(TL.getUnderlyingTInfo())->getType(); - Result = getDerived().RebuildUnaryTransformType(NewBase, - T->getUTTKind(), + if (getDerived().AlwaysRebuild() || AnyChanged) { + const TransformTraitType *T = TL.getTypePtr(); + SmallVector Args; + for (auto *TyInfo : NewTypeArgInfos) + Args.push_back(TyInfo->getType()); + Result = getDerived().RebuildTransformTraitType(Args, T->getTTKind(), TL.getKWLoc()); if (Result.isNull()) return QualType(); } - UnaryTransformTypeLoc NewTL = TLB.push(Result); + TransformTraitTypeLoc NewTL = TLB.push(Result); NewTL.setKWLoc(TL.getKWLoc()); NewTL.setParensRange(TL.getParensRange()); - NewTL.setUnderlyingTInfo(TL.getUnderlyingTInfo()); + for (unsigned I = 0; I < TL.getArgTInfo().size(); ++I) + NewTL.setArgInfo(I, NewTypeArgInfos[I]); + return Result; } -template +template QualType TreeTransform::TransformAutoType(TypeLocBuilder &TLB, AutoTypeLoc TL) { const AutoType *T = TL.getTypePtr(); @@ -6272,90 +6284,9 @@ // Transform type arguments. SmallVector NewTypeArgInfos; - for (unsigned i = 0, n = TL.getNumTypeArgs(); i != n; ++i) { - TypeSourceInfo *TypeArgInfo = TL.getTypeArgTInfo(i); - TypeLoc TypeArgLoc = TypeArgInfo->getTypeLoc(); - QualType TypeArg = TypeArgInfo->getType(); - if (auto PackExpansionLoc = TypeArgLoc.getAs()) { - AnyChanged = true; - - // We have a pack expansion. Instantiate it. - const auto *PackExpansion = PackExpansionLoc.getType() - ->castAs(); - SmallVector Unexpanded; - SemaRef.collectUnexpandedParameterPacks(PackExpansion->getPattern(), - Unexpanded); - assert(!Unexpanded.empty() && "Pack expansion without parameter packs?"); - - // Determine whether the set of unexpanded parameter packs can - // and should be expanded. - TypeLoc PatternLoc = PackExpansionLoc.getPatternLoc(); - bool Expand = false; - bool RetainExpansion = false; - Optional NumExpansions = PackExpansion->getNumExpansions(); - if (getDerived().TryExpandParameterPacks( - PackExpansionLoc.getEllipsisLoc(), PatternLoc.getSourceRange(), - Unexpanded, Expand, RetainExpansion, NumExpansions)) - return QualType(); - - if (!Expand) { - // We can't expand this pack expansion into separate arguments yet; - // just substitute into the pattern and create a new pack expansion - // type. - Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1); - - TypeLocBuilder TypeArgBuilder; - TypeArgBuilder.reserve(PatternLoc.getFullDataSize()); - QualType NewPatternType = getDerived().TransformType(TypeArgBuilder, - PatternLoc); - if (NewPatternType.isNull()) - return QualType(); - - QualType NewExpansionType = SemaRef.Context.getPackExpansionType( - NewPatternType, NumExpansions); - auto NewExpansionLoc = TLB.push(NewExpansionType); - NewExpansionLoc.setEllipsisLoc(PackExpansionLoc.getEllipsisLoc()); - NewTypeArgInfos.push_back( - TypeArgBuilder.getTypeSourceInfo(SemaRef.Context, NewExpansionType)); - continue; - } - - // Substitute into the pack expansion pattern for each slice of the - // pack. - for (unsigned ArgIdx = 0; ArgIdx != *NumExpansions; ++ArgIdx) { - Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), ArgIdx); - - TypeLocBuilder TypeArgBuilder; - TypeArgBuilder.reserve(PatternLoc.getFullDataSize()); - - QualType NewTypeArg = getDerived().TransformType(TypeArgBuilder, - PatternLoc); - if (NewTypeArg.isNull()) - return QualType(); - - NewTypeArgInfos.push_back( - TypeArgBuilder.getTypeSourceInfo(SemaRef.Context, NewTypeArg)); - } - - continue; - } - - TypeLocBuilder TypeArgBuilder; - TypeArgBuilder.reserve(TypeArgLoc.getFullDataSize()); - QualType NewTypeArg = getDerived().TransformType(TypeArgBuilder, TypeArgLoc); - if (NewTypeArg.isNull()) - return QualType(); - - // If nothing changed, just keep the old TypeSourceInfo. - if (NewTypeArg == TypeArg) { - NewTypeArgInfos.push_back(TypeArgInfo); - continue; - } - - NewTypeArgInfos.push_back( - TypeArgBuilder.getTypeSourceInfo(SemaRef.Context, NewTypeArg)); - AnyChanged = true; - } + if (getDerived().TransformTypeSourceListAndExpandPacks( + TL.getTypeArgTInfoRef(), AnyChanged, NewTypeArgInfos)) + return QualType(); QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || AnyChanged) { @@ -10466,20 +10397,19 @@ Old->requiresADL(), &TransArgs); } -template -ExprResult -TreeTransform::TransformTypeTraitExpr(TypeTraitExpr *E) { - bool ArgChanged = false; - SmallVector Args; - for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) { - TypeSourceInfo *From = E->getArg(I); +template +bool TreeTransform::TransformTypeSourceListAndExpandPacks( + ArrayRef InArgs, bool &ArgChanged, + SmallVectorImpl &Args) { + for (unsigned I = 0, N = InArgs.size(); I != N; ++I) { + TypeSourceInfo *From = InArgs[I]; TypeLoc FromTL = From->getTypeLoc(); if (!FromTL.getAs()) { TypeLocBuilder TLB; TLB.reserve(FromTL.getFullDataSize()); QualType To = getDerived().TransformType(TLB, FromTL); if (To.isNull()) - return ExprError(); + return true; if (To == From->getType()) Args.push_back(From); @@ -10510,27 +10440,27 @@ Unexpanded, Expand, RetainExpansion, NumExpansions)) - return ExprError(); + return true; if (!Expand) { // The transform has determined that we should perform a simple // transformation on the pack expansion, producing another pack // expansion. - Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1); + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, -1); TypeLocBuilder TLB; TLB.reserve(From->getTypeLoc().getFullDataSize()); QualType To = getDerived().TransformType(TLB, PatternTL); if (To.isNull()) - return ExprError(); + return true; To = getDerived().RebuildPackExpansionType(To, PatternTL.getSourceRange(), ExpansionTL.getEllipsisLoc(), NumExpansions); if (To.isNull()) - return ExprError(); + return true; PackExpansionTypeLoc ToExpansionTL = TLB.push(To); @@ -10547,7 +10477,7 @@ TLB.reserve(PatternTL.getFullDataSize()); QualType To = getDerived().TransformType(TLB, PatternTL); if (To.isNull()) - return ExprError(); + return true; if (To->containsUnexpandedParameterPack()) { To = getDerived().RebuildPackExpansionType(To, @@ -10555,7 +10485,7 @@ ExpansionTL.getEllipsisLoc(), NumExpansions); if (To.isNull()) - return ExprError(); + return true; PackExpansionTypeLoc ToExpansionTL = TLB.push(To); @@ -10577,20 +10507,30 @@ QualType To = getDerived().TransformType(TLB, PatternTL); if (To.isNull()) - return ExprError(); + return true; To = getDerived().RebuildPackExpansionType(To, PatternTL.getSourceRange(), ExpansionTL.getEllipsisLoc(), NumExpansions); if (To.isNull()) - return ExprError(); + return true; PackExpansionTypeLoc ToExpansionTL = TLB.push(To); ToExpansionTL.setEllipsisLoc(ExpansionTL.getEllipsisLoc()); Args.push_back(TLB.getTypeSourceInfo(SemaRef.Context, To)); } + return false; +} + +template +ExprResult TreeTransform::TransformTypeTraitExpr(TypeTraitExpr *E) { + bool ArgChanged = false; + SmallVector Args; + if (getDerived().TransformTypeSourceListAndExpandPacks(E->getArgs(), + ArgChanged, Args)) + return ExprError(); if (!getDerived().AlwaysRebuild() && !ArgChanged) return E; @@ -12477,11 +12417,11 @@ return SemaRef.BuildDecltypeType(E, Loc); } -template -QualType TreeTransform::RebuildUnaryTransformType(QualType BaseType, - UnaryTransformType::UTTKind UKind, - SourceLocation Loc) { - return SemaRef.BuildUnaryTransformType(BaseType, UKind, Loc); +template +QualType TreeTransform::RebuildTransformTraitType( + ArrayRef ArgTypes, TransformTraitType::TTKind TKind, + SourceLocation Loc) { + return SemaRef.BuildTransformTraitType(ArgTypes, TKind, Loc); } template Index: lib/Serialization/ASTReader.cpp =================================================================== --- lib/Serialization/ASTReader.cpp +++ lib/Serialization/ASTReader.cpp @@ -6092,11 +6092,15 @@ return Context.getDecltypeType(ReadExpr(*Loc.F), UnderlyingType); } - case TYPE_UNARY_TRANSFORM: { - QualType BaseType = readType(*Loc.F, Record, Idx); - QualType UnderlyingType = readType(*Loc.F, Record, Idx); - UnaryTransformType::UTTKind UKind = (UnaryTransformType::UTTKind)Record[2]; - return Context.getUnaryTransformType(BaseType, UnderlyingType, UKind); + case TYPE_TRANSFORM_TRAIT: { + SmallVector ArgTypes; + unsigned NumArgs = (unsigned)Record[Idx++]; + for (unsigned I = 0; I < NumArgs; ++I) + ArgTypes.push_back(readType(*Loc.F, Record, Idx)); + QualType TransformedType = readType(*Loc.F, Record, Idx); + TransformTraitType::TTKind TKind = + (TransformTraitType::TTKind)Record[Idx++]; + return Context.getTransformTraitType(ArgTypes, TransformedType, TKind); } case TYPE_AUTO: { @@ -6578,11 +6582,15 @@ TL.setNameLoc(ReadSourceLocation()); } -void TypeLocReader::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) { +void TypeLocReader::VisitTransformTraitTypeLoc(TransformTraitTypeLoc TL) { TL.setKWLoc(ReadSourceLocation()); TL.setLParenLoc(ReadSourceLocation()); TL.setRParenLoc(ReadSourceLocation()); - TL.setUnderlyingTInfo(GetTypeSourceInfo()); + unsigned Size = Record[Idx++]; + SmallVector ArgTInfo; + for (unsigned I = 0; I < Size; ++I) + ArgTInfo.push_back(GetTypeSourceInfo()); + TL.setArgTInfo(ArgTInfo); } void TypeLocReader::VisitAutoTypeLoc(AutoTypeLoc TL) { Index: lib/Serialization/ASTWriter.cpp =================================================================== --- lib/Serialization/ASTWriter.cpp +++ lib/Serialization/ASTWriter.cpp @@ -358,11 +358,14 @@ Code = TYPE_DECLTYPE; } -void ASTTypeWriter::VisitUnaryTransformType(const UnaryTransformType *T) { - Record.AddTypeRef(T->getBaseType()); - Record.AddTypeRef(T->getUnderlyingType()); - Record.push_back(T->getUTTKind()); - Code = TYPE_UNARY_TRANSFORM; +void ASTTypeWriter::VisitTransformTraitType(const TransformTraitType *T) { + auto ArgTys = T->getArgs(); + Record.push_back(ArgTys.size()); + for (auto Ty : ArgTys) + Record.AddTypeRef(Ty); + Record.AddTypeRef(T->getTransformedType()); + Record.push_back(T->getTTKind()); + Code = TYPE_TRANSFORM_TRAIT; } void ASTTypeWriter::VisitAutoType(const AutoType *T) { @@ -730,11 +733,14 @@ Record.AddSourceLocation(TL.getNameLoc()); } -void TypeLocWriter::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) { +void TypeLocWriter::VisitTransformTraitTypeLoc(TransformTraitTypeLoc TL) { Record.AddSourceLocation(TL.getKWLoc()); Record.AddSourceLocation(TL.getLParenLoc()); Record.AddSourceLocation(TL.getRParenLoc()); - Record.AddTypeSourceInfo(TL.getUnderlyingTInfo()); + ArrayRef ArgTInfo = TL.getArgTInfo(); + Record.push_back(ArgTInfo.size()); + for (auto *TSI : ArgTInfo) + Record.AddTypeSourceInfo(TSI); } void TypeLocWriter::VisitAutoTypeLoc(AutoTypeLoc TL) { @@ -1221,7 +1227,7 @@ RECORD(TYPE_ATTRIBUTED); RECORD(TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK); RECORD(TYPE_AUTO); - RECORD(TYPE_UNARY_TRANSFORM); + RECORD(TYPE_TRANSFORM_TRAIT); RECORD(TYPE_ATOMIC); RECORD(TYPE_DECAYED); RECORD(TYPE_ADJUSTED); Index: test/CodeGenCXX/mangle.cpp =================================================================== --- test/CodeGenCXX/mangle.cpp +++ test/CodeGenCXX/mangle.cpp @@ -1113,6 +1113,7 @@ // CHECK-LABEL: @_ZN6test552fnINS_1EEEEvT_U3eutS2_ } + namespace test56 { struct A { A *operator->(); int n; } a; template void f(decltype(a->n + N)) {} Index: test/SemaCXX/underlying_type.cpp =================================================================== --- test/SemaCXX/underlying_type.cpp +++ test/SemaCXX/underlying_type.cpp @@ -10,7 +10,10 @@ struct is_same_type { static const bool value = true; }; - +// expected-error@+1 {{C++ requires a type}} +__underlying_type() x; // expected-error {{type trait requires 1 argument; have 0 arguments}} +// expected-error@+1 {{C++ requires a type}} +__underlying_type(int, int) y; // expected-error {{type trait requires 1 argument; have 2 arguments}} __underlying_type(int) a; // expected-error {{only enumeration types}} __underlying_type(struct b) c; // expected-error {{only enumeration types}} @@ -26,6 +29,17 @@ static_assert(is_same_type::value, "h has the wrong type"); +template +struct TestParse { + // expected-error@+2 {{type trait requires 1 argument; have 0 arguments}} + // expected-error@+1 {{type trait requires 1 argument; have 2 arguments}} + using type = __underlying_type(Args...); +}; +static_assert(is_same_type::type, char>::value, "wrong type"); +template struct TestParse<>; // expected-note {{requested here}} +template struct TestParse; // expected-note {{requested here}} + + template struct underlying_type { typedef __underlying_type(T) type; // expected-error {{only enumeration types}}