Index: include/clang/AST/ASTContext.h =================================================================== --- include/clang/AST/ASTContext.h +++ include/clang/AST/ASTContext.h @@ -190,8 +190,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; @@ -1487,9 +1487,10 @@ /// C++11 decltype. QualType getDecltypeType(Expr *e, QualType UnderlyingType) const; - /// Unary type transforms - QualType getUnaryTransformType(QualType BaseType, QualType UnderlyingType, - UnaryTransformType::UTTKind UKind) const; + /// Type trait transformations + QualType getTransformTraitType(ArrayRef ArgTypes, + QualType TransformedType, + TransformTraitType::TTKind TKind) const; /// 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 @@ -1622,6 +1622,18 @@ unsigned Keyword : 2; }; + class TransformTraitTypeBitfields { + friend class TransformTraitType; + + unsigned : NumTypeBits; + + /// The transformation trait kind + unsigned TTKind : 1; + + /// The number of type arguments + unsigned NumArgs : 31 - NumTypeBits; + }; + union { TypeBitfields TypeBits; ArrayTypeBitfields ArrayTypeBits; @@ -1633,6 +1645,7 @@ ReferenceTypeBitfields ReferenceTypeBits; TypeWithKeywordBitfields TypeWithKeywordBits; VectorTypeBitfields VectorTypeBits; + TransformTraitTypeBitfields TransformTraitTypeBits; }; private: @@ -3995,38 +4008,47 @@ }; /// 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; + QualType *ArgStorage; /// 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, + TransformTraitType(const ASTContext &Ctx, 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 TransformTraitTypeBits.NumArgs; } + ArrayRef getArgs() const { + return llvm::makeArrayRef(ArgStorage, getNumArgs()); + } - UTTKind getUTTKind() const { return UKind; } + QualType getTransformedType() const { return TransformedType; } + QualType getArg(unsigned N) const { + assert(N < getNumArgs() && "invalid index"); + return ArgStorage[N]; + } + + static StringRef getName(TTKind K); + StringRef getName() const { return getName(getTTKind()); } + + TTKind getTTKind() const { + return static_cast(TransformTraitTypeBits.TTKind); + } static bool classof(const Type *T) { - return T->getTypeClass() == UnaryTransform; + return T->getTypeClass() == TransformTrait; } }; @@ -4035,21 +4057,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()); + } + + TypeSourceInfo *getArgInfo(unsigned I) { + assert(I < getNumArgs()); + return getArgLocArray()[I]; } - void setUnderlyingTInfo(TypeSourceInfo *TInfo) { - getLocalData()->UnderlyingTInfo = TInfo; + 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,14 @@ } void initializeLocal(ASTContext &Context, SourceLocation Loc); + + unsigned getExtraLocalDataSize() const { + return this->getNumArgs() * sizeof(TypeSourceInfo *); + } + + unsigned getExtraLocalDataAlignment() const { + 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 @@ -5288,6 +5288,16 @@ extern const AstTypeMatcher templateSpecializationType; +/// Matches types nodes representing type-trait transformations. +/// +/// Given: +/// \code +/// typedef __underlying_type(T) type; +/// \endcode +/// transformTraitType() +/// matches "__underlying_type(T)" +extern const AstTypeMatcher transformTraitType; + /// Matches types nodes representing unary type transformations. /// /// Given: @@ -5296,7 +5306,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; +} /// 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}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 @@ -892,11 +892,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/Parse/Parser.h =================================================================== --- include/clang/Parse/Parser.h +++ include/clang/Parse/Parser.h @@ -2505,7 +2505,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/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -1647,8 +1647,18 @@ /// 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, + + TypeResult ActOnTransformTraitType(ArrayRef ArgTypes, + TransformTraitType::TTKind Kind, + SourceLocation KWLoc, + SourceRange ParenRange); + + QualType ComputeTransformTraitResultType(ArrayRef ArgTypes, + TransformTraitType::TTKind Kind, + SourceLocation Loc); + + 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 @@ -1142,8 +1142,8 @@ /// A AutoType record. TYPE_AUTO = 38, - /// A UnaryTransformType record. - TYPE_UNARY_TRANSFORM = 39, + /// A TransformTraitType record. + TYPE_TRANSFORM_TRAIT = 39, /// An AtomicType record. TYPE_ATOMIC = 40, Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -3047,7 +3047,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: @@ -4686,38 +4686,44 @@ return QualType(dt, 0); } -/// getUnaryTransformationType - 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()) { +/// We don't unique these, since the memory savings are minimal and these are +/// rare. +QualType +ASTContext::getTransformTraitType(ArrayRef ArgTypes, + QualType TransformedType, + TransformTraitType::TTKind Kind) const { + assert(!TransformedType.isNull()); + TransformTraitType *ut = nullptr; + + bool IsDependent = TransformedType->isDependentType(); + + if (IsDependent) { + 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( + *this, ArgTypes, DependentTy, 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(*this, 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()); Index: lib/AST/ASTImporter.cpp =================================================================== --- lib/AST/ASTImporter.cpp +++ lib/AST/ASTImporter.cpp @@ -129,7 +129,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 @@ -807,15 +807,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 {}; - 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 @@ -508,13 +508,22 @@ return false; break; - case Type::UnaryTransform: - if (!IsStructurallyEquivalent( - Context, cast(T1)->getUnderlyingType(), - cast(T2)->getUnderlyingType())) + case Type::TransformTrait: { + const TransformTraitType *TT1 = cast(T1); + const TransformTraitType *TT2 = cast(T2); + if (TT1->getTTKind() != TT2->getTTKind()) + return false; + 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. @@ -3267,20 +3267,37 @@ Out << 'E'; } -void CXXNameMangler::mangleType(const UnaryTransformType *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; - } +void CXXNameMangler::mangleType(const TransformTraitType *T) { + // TransformTraitType's uses a non-standard mangling with the intent to + // suggest it as a Itanium ABI extension. + // + // ::= + // u [] # vendor extended type + + // If this type isn't dependent, simply mangle it as the transformed type + // since they are equivalent. Otherwise, we need to record the dependent type. + if (!T->isDependentType()) { + mangleType(T->getTransformedType()); + return; } - mangleType(T->getBaseType()); + Out << "u"; + + // mangle the source name. + StringRef Ident = + TransformTraitType::GetTransformTraitIdentifier(T->getTTKind()); + Out << Ident.size() << Ident; + + assert(T->getNumArgs() && "Empty argument list for transformation trait?"); + + Out << "I"; + + // mangle each argument type. + for (auto Ty : T->getArgs()) + mangleType(Ty); + + // Disambiguate the end of the argument list. + Out << "E"; } void CXXNameMangler::mangleType(const AutoType *T) { Index: lib/AST/MicrosoftMangle.cpp =================================================================== --- lib/AST/MicrosoftMangle.cpp +++ lib/AST/MicrosoftMangle.cpp @@ -2650,13 +2650,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 @@ -977,10 +977,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) @@ -3083,20 +3107,41 @@ E->Profile(ID, Context, true); } -UnaryTransformType::UnaryTransformType(QualType BaseType, - QualType UnderlyingType, - UTTKind UKind, +TransformTraitType::TransformTraitType(const ASTContext &Ctx, + 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), + TransformedType(TransformedTy) { + TransformTraitTypeBits.TTKind = TKind; + TransformTraitTypeBits.NumArgs = ArgTys.size(); + ArgStorage = (QualType *)Ctx.Allocate(sizeof(QualType) * ArgTys.size(), + alignof(QualType)); + assert(!TransformedTy.isNull()); + this->setDependent(TransformedTy->isDependentType()); + this->setVariablyModified(TransformedTy->isVariablyModifiedType()); + + for (unsigned I = 0, NumArgs = ArgTys.size(); I < NumArgs; ++I) { + QualType T = ArgTys[I]; + new ((void *)(ArgStorage + I)) QualType(T); + if (T->isInstantiationDependentType()) + this->setInstantiationDependent(true); + if (T->containsUnexpandedParameterPack()) + this->setContainsUnexpandedParameterPack(true); + } +} + +StringRef TransformTraitType::getName(TTKind Kind) { + switch (Kind) { + case TransformTraitType::EnumUnderlyingType: + return "__underlying_type"; + } + llvm_unreachable("unhandled case"); +} -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(C, ArgTys, C.DependentTy, TKind, QualType()) {} TagType::TagType(TypeClass TC, const TagDecl *D, QualType can) : Type(TC, can, D->isDependentType(), @@ -3717,7 +3762,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 @@ -470,13 +470,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 @@ -203,7 +203,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: @@ -931,32 +931,32 @@ 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; + OS << T->getName() << "("; + + for (unsigned I = 0; I != T->getNumArgs(); ++I) { + print(T->getArg(I), OS, StringRef()); + if ((I + 1) != T->getNumArgs()) + OS << ", "; } - printBefore(T->getBaseType(), OS); + OS << ')'; + spaceBeforePlaceHolder(OS); } -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 @@ -811,7 +811,7 @@ const AstTypeMatcher typedefType; const AstTypeMatcher enumType; const AstTypeMatcher templateSpecializationType; -const AstTypeMatcher unaryTransformType; +const AstTypeMatcher transformTraitType; const AstTypeMatcher recordType; const AstTypeMatcher tagType; const AstTypeMatcher elaboratedType; Index: lib/CodeGen/CGDebugInfo.cpp =================================================================== --- lib/CodeGen/CGDebugInfo.cpp +++ lib/CodeGen/CGDebugInfo.cpp @@ -2639,8 +2639,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(); @@ -2834,7 +2834,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 @@ -2118,7 +2118,7 @@ case Type::Paren: case Type::TypeOf: - case Type::UnaryTransform: + case Type::TransformTrait: case Type::Attributed: case Type::SubstTemplateTypeParm: case Type::PackExpansion: Index: lib/Parse/ParseDecl.cpp =================================================================== --- lib/Parse/ParseDecl.cpp +++ lib/Parse/ParseDecl.cpp @@ -3770,7 +3770,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,66 @@ PP.AnnotateCachedTokens(Tok); } -void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) { - assert(Tok.is(tok::kw___underlying_type) && - "Not an underlying type specifier"); - SourceLocation StartLoc = ConsumeToken(); - BalancedDelimiterTracker T(*this, tok::l_paren); - if (T.expectAndConsume(diag::err_expected_lparen_after, - "__underlying_type", tok::r_paren)) { +void Parser::ParseTransformTraitTypeSpecifier(DeclSpec &DS) { + auto Error = [&]() { + DS.SetTypeSpecError(); return; - } + }; + auto KindInfo = + [&]() -> std::pair { + using EnumKind = TransformTraitType::TTKind; + switch (Tok.getKind()) { + case tok::kw___underlying_type: + return {EnumKind::EnumUnderlyingType, clang::TST_underlyingType}; + default: + llvm_unreachable("Not a transformation trait type specifier"); + } + }(); - TypeResult Result = ParseTypeName(); - if (Result.isInvalid()) { - SkipUntil(tok::r_paren, StopAtSemi); - return; + SourceLocation StartLoc = ConsumeToken(); + BalancedDelimiterTracker Parens(*this, tok::l_paren); + if (Parens.expectAndConsume()) + return Error(); + + SmallVector Args; + if (Tok.isNot(tok::r_paren)) { + do { + // Parse the next type. + TypeResult Ty = ParseTypeName(); + if (Ty.isInvalid()) { + Parens.skipToEnd(); + return Error(); + } + + // Parse the ellipsis, if present. + if (Tok.is(tok::ellipsis)) { + Ty = Actions.ActOnPackExpansion(Ty.get(), ConsumeToken()); + if (Ty.isInvalid()) { + Parens.skipToEnd(); + return Error(); + } + } + + // Add this type to the list of arguments. + Args.push_back(Ty.get()); + } while (TryConsumeToken(tok::comma)); } + if (Parens.consumeClose()) + return Error(); - // Match the ')' - T.consumeClose(); - if (T.getCloseLocation().isInvalid()) - return; + TypeResult TyRes = Actions.ActOnTransformTraitType( + Args, KindInfo.first, StartLoc, Parens.getRange()); + if (TyRes.isInvalid()) + return Error(); + // TST const char *PrevSpec = nullptr; unsigned DiagID; - if (DS.SetTypeSpecType(DeclSpec::TST_underlyingType, StartLoc, PrevSpec, - DiagID, Result.get(), + if (DS.SetTypeSpecType(KindInfo.second, StartLoc, PrevSpec, DiagID, TyRes.get(), 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 @@ -370,8 +370,13 @@ if (Expr *E = DS.getRepAsExpr()) return E->getType()->isFunctionType(); return false; - - case TST_underlyingType: + + case TST_underlyingType: { + QualType QT = DS.getRepAsType().get(); + assert(!QT.isNull()); + return QT->isFunctionType(); + } + case TST_typename: case TST_typeofType: { QualType QT = DS.getRepAsType().get(); Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -3940,7 +3940,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 @@ -5382,8 +5382,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 @@ -1951,7 +1951,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: @@ -5369,13 +5369,14 @@ 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) { + for (auto Ty : TT->getArgs()) + MarkUsedTemplateParameters(Ctx, Ty, OnlyDeduced, Depth, Used); + } break; - + } case Type::PackExpansion: MarkUsedTemplateParameters(Ctx, cast(T)->getPattern(), Index: lib/Sema/SemaType.cpp =================================================================== --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -1543,18 +1543,15 @@ } 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: { + ParsedType ParsedTT = DS.getRepAsType(); + Result = S.GetTypeFromParser(ParsedTT); if (Result.isNull()) { Result = Context.IntTy; declarator.setInvalidType(true); } break; - + } case DeclSpec::TST_auto: Result = Context.getAutoType(QualType(), AutoTypeKeyword::Auto, false); break; @@ -5375,16 +5372,14 @@ 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); + TypeSourceInfo *RepTInfo = nullptr; + Sema::GetTypeFromParser(DS.getRepAsType(), &RepTInfo); + TL.copy(RepTInfo->getTypeLoc()); } + void VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { // By default, use the source location of the type specifier. TL.setBuiltinLoc(DS.getTypeSpecTypeLoc()); @@ -8068,39 +8063,130 @@ return Context.getDecltypeType(E, getDecltypeForExpr(*this, 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 bool CheckTransformTraitArity(Sema &S, TransformTraitType::TTKind Kind, + unsigned NumArgs, SourceLocation Loc, SourceRange R) { + unsigned Arity; + bool IsVariadic = false; + switch (Kind) { + case TransformTraitType::EnumUnderlyingType: + Arity = 1; + break; + } + + struct DiagInfo { + unsigned ReqNumArgs; + unsigned SelectOne; + }; + auto DiagSelect = [&]() -> Optional { + if (NumArgs == 0) + return DiagInfo{Arity, 0}; + if (Arity && !IsVariadic && Arity != NumArgs) + return DiagInfo{Arity, 0}; + if (Arity && IsVariadic && NumArgs < Arity) + return DiagInfo{Arity, 1}; + 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 << R; + return true; + } + return false; +} + +TypeResult Sema::ActOnTransformTraitType(ArrayRef ParsedArgs, + TransformTraitType::TTKind Kind, + SourceLocation KWLoc, + SourceRange ParenRange) { + SmallVector ArgTInfos; + SmallVector ArgTypes; + ArgTInfos.reserve(ParsedArgs.size()); + ArgTypes.reserve(ParsedArgs.size()); + + for (auto &PT : ParsedArgs) { + TypeSourceInfo *ArgTypeInfo = nullptr; + QualType NewArg = GetTypeFromParser(PT, &ArgTypeInfo); + assert(ArgTypeInfo && "No type source info?"); + ArgTypes.push_back(NewArg); + ArgTInfos.push_back(ArgTypeInfo); + } + QualType Result = BuildTransformTraitType(ArgTypes, Kind, KWLoc); + if (Result.isNull()) + return TypeResult(/*IsInvalid*/true); - EnumDecl *ED = BaseType->getAs()->getDecl(); - assert(ED && "EnumType has no EnumDecl"); + // Create source information for this type. + TypeSourceInfo *ResultTInfo = Context.CreateTypeSourceInfo(Result); + TypeLoc ResultTL = ResultTInfo->getTypeLoc(); - DiagnoseUseOfDecl(ED, Loc); + auto TTT = ResultTL.castAs(); + TTT.setKWLoc(KWLoc); + TTT.setParensRange(ParenRange); + if (TTT.getNumArgs() > 0) { + assert(TTT.getNumArgs() == ArgTInfos.size()); + TTT.setArgTInfo(ArgTInfos); + } - Underlying = ED->getIntegerType(); - assert(!Underlying.isNull()); - } - return Context.getUnaryTransformType(BaseType, Underlying, - UnaryTransformType::EnumUnderlyingType); + return CreateParsedType(Result, ResultTInfo); +} + +QualType Sema::ComputeTransformTraitResultType(ArrayRef ArgTypes, + TransformTraitType::TTKind TKind, + SourceLocation Loc) { + auto Error = []() { return QualType(); }; + bool DelayChecking = llvm::any_of(ArgTypes, [](QualType Ty) { + return Ty->isDependentType() || + Ty->containsUnexpandedParameterPack(); + }); + + // Delay all checking while any of the arguments are instantiation dependent. + if (DelayChecking) + return Context.DependentTy; + + if (CheckTransformTraitArity(*this, TKind, ArgTypes.size(), Loc, SourceRange(Loc))) + return Error(); + + switch (TKind) { + case TransformTraitType::EnumUnderlyingType: { + assert(ArgTypes.size() == 1); + if (ArgTypes[0]->isDependentType()) + return Context.DependentTy; + + QualType BaseType = ArgTypes[0]; + if (!BaseType->isEnumeralType()) { + Diag(Loc, diag::err_only_enums_have_underlying_types); + return Error(); } + // 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 Error(); + } + + EnumDecl *ED = BaseType->getAs()->getDecl(); + assert(ED && "EnumType has no EnumDecl"); + + DiagnoseUseOfDecl(ED, Loc); + assert(!ED->getIntegerType().isNull()); + return ED->getIntegerType(); } - llvm_unreachable("unknown unary transform type"); + } + + llvm_unreachable("unknown transform type"); +} + +QualType Sema::BuildTransformTraitType(ArrayRef ArgTypes, + TransformTraitType::TTKind TKind, + SourceLocation Loc) { + QualType ResultType = ComputeTransformTraitResultType(ArgTypes, TKind, Loc); + if (ResultType.isNull()) + return QualType(); + return Context.getTransformTraitType(ArgTypes, ResultType, TKind); } QualType Sema::BuildAtomicType(QualType T, SourceLocation Loc) { Index: lib/Sema/TreeTransform.h =================================================================== --- lib/Sema/TreeTransform.h +++ lib/Sema/TreeTransform.h @@ -622,6 +622,9 @@ TypeLocBuilder &TLB, DependentTemplateSpecializationTypeLoc TL, NestedNameSpecifierLoc QualifierLoc); + bool TransformTypeList(ArrayRef InArgs, bool &ArgChanged, + SmallVectorImpl &Args); + /// Transforms the parameters of a function type into the /// given vectors. /// @@ -888,9 +891,9 @@ /// By default, builds a new TypeOfType with the given underlying type. QualType RebuildTypeOfType(QualType Underlying); - /// Build a new unary transform type. - QualType RebuildUnaryTransformType(QualType BaseType, - UnaryTransformType::UTTKind UKind, + /// Build a new transform trait type. + QualType RebuildTransformTraitType(ArrayRef ArgTypes, + TransformTraitType::TTKind TKind, SourceLocation Loc); /// Build a new C++11 decltype type. @@ -5519,30 +5522,42 @@ 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().TransformTypeList(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; + Args.reserve(NewTypeArgInfos.size()); + 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); + assert(NewTL.getNumArgs() == NewTypeArgInfos.size()); + NewTL.setKWLoc(TL.getKWLoc()); NewTL.setParensRange(TL.getParensRange()); - NewTL.setUnderlyingTInfo(TL.getUnderlyingTInfo()); + for (unsigned I = 0, Size = NewTypeArgInfos.size(); I < Size; ++I) + NewTL.setArgInfo(I, NewTypeArgInfos[I]); + return Result; } -template +template QualType TreeTransform::TransformAutoType(TypeLocBuilder &TLB, AutoTypeLoc TL) { const AutoType *T = TL.getTypePtr(); @@ -6271,90 +6286,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().TransformTypeList(TL.getTypeArgTInfoRef(), AnyChanged, + NewTypeArgInfos)) + return QualType(); QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || AnyChanged) { @@ -10471,20 +10405,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::TransformTypeList( + 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); @@ -10515,27 +10448,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); @@ -10552,7 +10485,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, @@ -10560,7 +10493,7 @@ ExpansionTL.getEllipsisLoc(), NumExpansions); if (To.isNull()) - return ExprError(); + return true; PackExpansionTypeLoc ToExpansionTL = TLB.push(To); @@ -10582,20 +10515,29 @@ 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().TransformTypeList(E->getArgs(), ArgChanged, Args)) + return ExprError(); if (!getDerived().AlwaysRebuild() && !ArgChanged) return E; @@ -12482,11 +12424,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 @@ -6100,11 +6100,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: { @@ -6587,11 +6591,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) { @@ -731,11 +734,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) { @@ -1222,7 +1228,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 @@ -1110,9 +1110,13 @@ void fn(T, __underlying_type(T)) {} template void fn(E, __underlying_type(E)); -// CHECK-LABEL: @_ZN6test552fnINS_1EEEEvT_U3eutS2_ +// CHECK-LABEL: @_ZN6test552fnINS_1EEEEvT_u17__underlying_typeIS2_E + +void fn2(E, __underlying_type(E)) {} +// CHECK-LABEL: @_ZN6test553fn2ENS_1EEj } + 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,8 @@ struct is_same_type { static const bool value = true; }; - +__underlying_type() x; // expected-error {{type trait requires 1 argument; have 0 arguments}} +__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 +27,31 @@ static_assert(is_same_type::value, "h has the wrong type"); +template struct TypeList {}; + +template +struct TestParse; + +template struct MyTest {}; + +template +struct TestParse> { + using type = __underlying_type(Args...); +}; + +template +struct TestParse, TypeList> { + // expected-error@+2 2 {{type trait requires 1 argument; have 2 arguments}} + // expected-error@+1 {{type trait requires 1 argument; have 0 arguments}} + using type = __underlying_type(Args1..., Args2...); +}; +static_assert(is_same_type>::type, char>::value, "wrong type"); +static_assert(is_same_type, TypeList<>>::type, char>::value, "wrong type"); +template struct TestParse, TypeList<>>; // expected-note {{requested here}} +template struct TestParse, TypeList<>>; // expected-note {{requested here}} +template struct TestParse, TypeList>; // expected-note {{requested here}} + + template struct underlying_type { typedef __underlying_type(T) type; // expected-error {{only enumeration types}} @@ -38,7 +64,7 @@ using uint = unsigned; enum class foo : uint { bar }; - + static_assert(is_same_type::type, unsigned>::value, "foo has the wrong underlying type");