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,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; @@ -1625,6 +1637,7 @@ ReferenceTypeBitfields ReferenceTypeBits; TypeWithKeywordBitfields TypeWithKeywordBits; VectorTypeBitfields VectorTypeBits; + TransformTraitTypeBitfields TransformTraitTypeBits; }; private: @@ -3971,38 +3984,44 @@ }; /// 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()); + } + + QualType getTransformedType() const { return TransformedType; } + QualType getArg(unsigned N) const { + assert(N < getNumArgs() && "invalid index"); + return ArgStorage[N]; + } - UTTKind getUTTKind() const { return UKind; } + TTKind getTTKind() const { + return static_cast(TransformTraitTypeBits.TTKind); + } static bool classof(const Type *T) { - return T->getTypeClass() == UnaryTransform; + return T->getTypeClass() == TransformTrait; } }; @@ -4011,21 +4030,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}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/Parse/Parser.h =================================================================== --- include/clang/Parse/Parser.h +++ include/clang/Parse/Parser.h @@ -37,6 +37,7 @@ class CorrectionCandidateCallback; class DeclGroupRef; class DiagnosticBuilder; + class PartialDiagnostic; class Parser; class ParsingDeclRAIIObject; class ParsingDeclSpec; @@ -916,6 +917,7 @@ DiagnosticBuilder Diag(unsigned DiagID) { return Diag(Tok, DiagID); } + DiagnosticBuilder Diag(SourceLocation Loc, const PartialDiagnostic &PD); private: void SuggestParentheses(SourceLocation Loc, unsigned DK, @@ -2407,7 +2409,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,13 @@ /// 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, + + Optional + CheckTransformTraitArity(TransformTraitType::TTKind, unsigned NumArgs, + SourceRange R); + + 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 @@ -1068,7 +1068,7 @@ TYPE_AUTO = 38, /// \brief A UnaryTransformType record. - TYPE_UNARY_TRANSFORM = 39, + TYPE_TRANSFORM_TRAIT = 39, /// \brief An AtomicType record. TYPE_ATOMIC = 40, Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -2975,7 +2975,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: @@ -4627,38 +4627,44 @@ 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) { + 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, 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(*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()); @@ -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,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. @@ -3233,20 +3233,22 @@ 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); + // Disambiguate the end of the argument list. + Out << "E"; + } else + mangleType(T->getTransformedType()); } 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) @@ -3041,20 +3065,33 @@ 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) {} - -DependentUnaryTransformType::DependentUnaryTransformType(const ASTContext &C, - QualType BaseType, - UTTKind UKind) - : UnaryTransformType(BaseType, C.DependentTy, UKind, QualType()) {} + : 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)); + for (unsigned I = 0, NumArgs = ArgTys.size(); I < NumArgs; ++I) { + QualType T = ArgTys[I]; + new ((void *)(ArgStorage + I)) QualType(T); + if (T->isDependentType()) + this->setDependent(true); + if (T->isInstantiationDependentType()) + this->setInstantiationDependent(true); + if (T->isVariablyModifiedType()) + this->setVariablyModified(true); + if (T->containsUnexpandedParameterPack()) + this->setContainsUnexpandedParameterPack(true); + } +} + +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(), @@ -3675,7 +3712,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: @@ -875,33 +875,36 @@ 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); } -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 @@ -2582,8 +2582,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(); @@ -2777,7 +2777,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 @@ -2095,7 +2095,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,71 @@ PP.AnnotateCachedTokens(Tok); } -void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) { - assert(Tok.is(tok::kw___underlying_type) && - "Not an underlying type specifier"); + +void Parser::ParseTransformTraitTypeSpecifier(DeclSpec &DS) { + + 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"); + } + }(); 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; + bool HasPackExpand = false; + if (Tok.isNot(tok::r_paren)) { + do { + // Parse the next type. + TypeResult Ty = ParseTypeName(); + if (Ty.isInvalid()) { + Parens.skipToEnd(); + return; + } - // Match the ')' - T.consumeClose(); - if (T.getCloseLocation().isInvalid()) + // Parse the ellipsis, if present. + if (Tok.is(tok::ellipsis)) { + HasPackExpand = true; + 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; + SourceLocation EndLoc = Parens.getCloseLocation(); + + if (!HasPackExpand) { + auto PDiag = Actions.CheckTransformTraitArity(KindInfo.first, Args.size(), + SourceRange(StartLoc)); + if (PDiag.hasValue()) { + Diag(EndLoc, PDiag.getValue()); + return; + } + } + + // 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, 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/Parse/Parser.cpp =================================================================== --- lib/Parse/Parser.cpp +++ lib/Parse/Parser.cpp @@ -15,6 +15,7 @@ #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclTemplate.h" +#include "clang/Basic/PartialDiagnostic.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/RAIIObjectsForParser.h" #include "clang/Sema/DeclSpec.h" @@ -77,6 +78,13 @@ return Diag(Tok.getLocation(), DiagID); } +DiagnosticBuilder Parser::Diag(SourceLocation Loc, + const PartialDiagnostic &PD) { + DiagnosticBuilder Builder(Diag(Loc, PD.getDiagID())); + PD.Emit(Builder); + return Builder; +} + /// \brief Emits a diagnostic suggesting parentheses surrounding a /// given range. /// 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 @@ -3890,7 +3890,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,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/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; @@ -5311,15 +5324,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. @@ -7970,39 +7986,93 @@ return Context.getDecltypeType(E, getDecltypeForExpr(*this, E)); } -QualType Sema::BuildUnaryTransformType(QualType BaseType, - UnaryTransformType::UTTKind UKind, +Optional +Sema::CheckTransformTraitArity(TransformTraitType::TTKind Kind, + unsigned NumArgs, 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(); + PartialDiagnostic PD = PDiag(diag::err_type_trait_arity); + PD << Info.ReqNumArgs << Info.SelectOne << (Info.ReqNumArgs != 1) + << (int)NumArgs << R; + return PD; + } + return None; +} + +QualType Sema::BuildTransformTraitType(ArrayRef ArgTypes, + TransformTraitType::TTKind TKind, 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(); - } + auto MakeTrait = [&](QualType TransformedType) { + return Context.getTransformTraitType(ArgTypes, TransformedType, TKind); + }; - EnumDecl *ED = BaseType->getAs()->getDecl(); - assert(ED && "EnumType has no EnumDecl"); + bool IsInstantDependent = llvm::any_of(ArgTypes, [](QualType Ty) { + return Ty->isInstantiationDependentType() || + Ty->containsUnexpandedParameterPack(); + }); - DiagnoseUseOfDecl(ED, Loc); + // Delay all checking while any of the arguments are instantiation dependent. + if (IsInstantDependent) + return MakeTrait(Context.DependentTy); - Underlying = ED->getIntegerType(); - assert(!Underlying.isNull()); - } - return Context.getUnaryTransformType(BaseType, Underlying, - UnaryTransformType::EnumUnderlyingType); + if (auto ArityDiag = + CheckTransformTraitArity(TKind, ArgTypes.size(), SourceRange(Loc))) { + Diag(Loc, ArityDiag.getValue()); + return QualType(); + } + + switch (TKind) { + case TransformTraitType::EnumUnderlyingType: { + assert(ArgTypes.size() == 1); + if (ArgTypes[0]->isDependentType()) + return MakeTrait(Context.DependentTy); + + QualType BaseType = ArgTypes[0]; + if (!BaseType->isEnumeralType()) { + Diag(Loc, diag::err_only_enums_have_underlying_types); + return QualType(); + } + // The enum could be incomplete if we're parsing its definition or + // recovering from an error. + NamedDecl *FwdDecl = nullptr; + if (BaseType->isIncompleteType(&FwdDecl)) { + Diag(Loc, diag::err_underlying_type_of_incomplete_enum) << BaseType; + Diag(FwdDecl->getLocation(), diag::note_forward_declaration) << FwdDecl; + return QualType(); } + + EnumDecl *ED = BaseType->getAs()->getDecl(); + assert(ED && "EnumType has no EnumDecl"); + + DiagnoseUseOfDecl(ED, Loc); + assert(!ED->getIntegerType().isNull()); + return MakeTrait(ED->getIntegerType()); } - 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,9 @@ TypeLocBuilder &TLB, DependentTemplateSpecializationTypeLoc TL, NestedNameSpecifierLoc QualifierLoc); + bool TransformTypeList(ArrayRef InArgs, bool &ArgChanged, + SmallVectorImpl &Args); + /// \brief 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); - /// \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 +5523,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(); @@ -6272,90 +6287,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) { @@ -10466,20 +10400,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); @@ -10510,27 +10443,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 +10480,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 +10488,7 @@ ExpansionTL.getEllipsisLoc(), NumExpansions); if (To.isNull()) - return ExprError(); + return true; PackExpansionTypeLoc ToExpansionTL = TLB.push(To); @@ -10577,20 +10510,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; @@ -12477,11 +12419,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 @@ -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_U3eutS2_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,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,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 +66,7 @@ using uint = unsigned; enum class foo : uint { bar }; - + static_assert(is_same_type::type, unsigned>::value, "foo has the wrong underlying type");