From: Sean Hunt Date: Tue, 24 May 2011 22:41:36 +0000 (+0000) Subject: Implement a new type node, UnaryTransformType, designed to represent a X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ca63c200346c0ca9e00194ec6e34a5a7b0ed9321;p=clang Implement a new type node, UnaryTransformType, designed to represent a type that turns one type into another. This is used as the basis to implement __underlying_type properly - with TypeSourceInfo and proper behavior in the face of templates. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@132017 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index f519af712c..4f4d949735 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -779,6 +779,10 @@ public: /// getDecltypeType - C++0x decltype. QualType getDecltypeType(Expr *e) const; + /// getUnaryTransformType - unary type transforms + QualType getUnaryTransformType(QualType BaseType, QualType UnderlyingType, + UnaryTransformType::UTTKind UKind) const; + /// getAutoType - C++0x deduced auto type. QualType getAutoType(QualType DeducedType) const; diff --git a/include/clang/AST/CanonicalType.h b/include/clang/AST/CanonicalType.h index fb00d86301..2518814904 100644 --- a/include/clang/AST/CanonicalType.h +++ b/include/clang/AST/CanonicalType.h @@ -632,6 +632,14 @@ struct CanProxyAdaptor : public CanProxyBase { LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getUnderlyingType) }; +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) +}; + template<> struct CanProxyAdaptor : public CanProxyBase { LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(TagDecl *, getDecl) diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 33171bd003..d97bb376a0 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -750,6 +750,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(AutoType, { TRY_TO(TraverseType(T->getDeducedType())); }) @@ -966,6 +971,10 @@ DEF_TRAVERSE_TYPELOC(DecltypeType, { TRY_TO(TraverseStmt(TL.getTypePtr()->getUnderlyingExpr())); }) +DEF_TRAVERSE_TYPELOC(UnaryTransformType, { + TRY_TO(TraverseTypeLoc(TL.getUnderlyingTInfo()->getTypeLoc())); + }) + DEF_TRAVERSE_TYPELOC(AutoType, { TRY_TO(TraverseType(TL.getTypePtr()->getDeducedType())); }) diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 1e8642f76a..b6c6b5616c 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -2825,6 +2825,39 @@ public: Expr *E); }; +/// \brief A unary type transform, which is a type constructed from another +class UnaryTransformType : public Type { +public: + enum UTTKind { + EnumUnderlyingType + }; + +private: + /// The untransformed type. + QualType BaseType; + /// The transformed type if not dependent, otherwise the same as BaseType. + QualType UnderlyingType; + + UTTKind UKind; +protected: + UnaryTransformType(QualType BaseTy, QualType UnderlyingTy, UTTKind UKind, + QualType CanonicalTy); + friend class ASTContext; +public: + bool isSugared() const { return !isDependentType(); } + QualType desugar() const { return UnderlyingType; } + + QualType getUnderlyingType() const { return UnderlyingType; } + QualType getBaseType() const { return BaseType; } + + UTTKind getUTTKind() const { return UKind; } + + static bool classof(const Type *T) { + return T->getTypeClass() == UnaryTransform; + } + static bool classof(const UnaryTransformType *) { return true; } +}; + class TagType : public Type { /// Stores the TagDecl associated with this type. The decl may point to any /// TagDecl that declares the entity. diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h index a1df744c2a..f5669f7fc0 100644 --- a/include/clang/AST/TypeLoc.h +++ b/include/clang/AST/TypeLoc.h @@ -1410,6 +1410,53 @@ class DecltypeTypeLoc : public InheritingConcreteTypeLoc { }; +struct UnaryTransformTypeLocInfo { + // 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 { +public: + SourceLocation getKWLoc() const { return getLocalData()->KWLoc; } + void setKWLoc(SourceLocation Loc) { getLocalData()->KWLoc = Loc; } + + SourceLocation getLParenLoc() const { return getLocalData()->LParenLoc; } + void setLParenLoc(SourceLocation Loc) { getLocalData()->LParenLoc = Loc; } + + SourceLocation getRParenLoc() const { return getLocalData()->RParenLoc; } + void setRParenLoc(SourceLocation Loc) { getLocalData()->RParenLoc = Loc; } + + TypeSourceInfo* getUnderlyingTInfo() const { + return getLocalData()->UnderlyingTInfo; + } + void setUnderlyingTInfo(TypeSourceInfo *TInfo) { + getLocalData()->UnderlyingTInfo = TInfo; + } + + SourceRange getLocalSourceRange() const { + return SourceRange(getKWLoc(), getRParenLoc()); + } + + SourceRange getParensRange() const { + return SourceRange(getLParenLoc(), getRParenLoc()); + } + void setParensRange(SourceRange Range) { + setLParenLoc(Range.getBegin()); + setRParenLoc(Range.getEnd()); + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + setKWLoc(Loc); + setRParenLoc(Loc); + setLParenLoc(Loc); + } +}; + class AutoTypeLoc : public InheritingConcreteTypeLoc { diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def index b2591cc0fb..0792d0d9b3 100644 --- a/include/clang/AST/TypeNodes.def +++ b/include/clang/AST/TypeNodes.def @@ -84,6 +84,7 @@ NON_CANONICAL_TYPE(Typedef, Type) 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) ABSTRACT_TYPE(Tag, Type) TYPE(Record, TagType) TYPE(Enum, TagType) diff --git a/include/clang/Basic/Specifiers.h b/include/clang/Basic/Specifiers.h index 042fd02fbe..d21bda7d9a 100644 --- a/include/clang/Basic/Specifiers.h +++ b/include/clang/Basic/Specifiers.h @@ -54,7 +54,7 @@ namespace clang { TST_typeofType, TST_typeofExpr, TST_decltype, // C++0x decltype - TST_underlying_type, // __underlying_type for C++0x + TST_underlyingType, // __underlying_type for C++0x TST_auto, // C++0x auto TST_unknown_anytype, // __unknown_anytype extension TST_error // erroneous type diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h index d3e943ede0..be1f5f8c79 100644 --- a/include/clang/Sema/DeclSpec.h +++ b/include/clang/Sema/DeclSpec.h @@ -249,7 +249,7 @@ public: static const TST TST_typeofType = clang::TST_typeofType; static const TST TST_typeofExpr = clang::TST_typeofExpr; static const TST TST_decltype = clang::TST_decltype; - static const TST TST_underlying_type = clang::TST_underlying_type; + static const TST TST_underlyingType = clang::TST_underlyingType; static const TST TST_auto = clang::TST_auto; static const TST TST_unknown_anytype = clang::TST_unknown_anytype; static const TST TST_error = clang::TST_error; @@ -346,7 +346,7 @@ private: static bool isTypeRep(TST T) { return (T == TST_typename || T == TST_typeofType || - T == TST_underlying_type); + T == TST_underlyingType); } static bool isExprRep(TST T) { return (T == TST_typeofExpr || T == TST_decltype); diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index b6ee854a3b..2cbfd9f3d6 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -814,6 +814,9 @@ public: QualType BuildTypeofExprType(Expr *E, SourceLocation Loc); QualType BuildDecltypeType(Expr *E, SourceLocation Loc); + QualType BuildUnaryTransformType(QualType BaseType, + UnaryTransformType::UTTKind UKind, + SourceLocation Loc); //===--------------------------------------------------------------------===// // Symbol table / Decl tracking callbacks: SemaDecl.cpp. diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index ff02675898..ae87b29147 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -589,7 +589,9 @@ namespace clang { /// \brief A SubstTemplateTypeParmPackType record. TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK = 37, /// \brief A AutoType record. - TYPE_AUTO = 38 + TYPE_AUTO = 38, + /// \brief A UnaryTransformType record. + TYPE_UNARY_TRANSFORM = 39 }; /// \brief The type IDs for special types constructed by semantic diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index e664855067..f356c908e9 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -975,6 +975,9 @@ ASTContext::getTypeInfo(const Type *T) const { return getTypeInfo(cast(T)->getUnderlyingExpr()->getType() .getTypePtr()); + case Type::UnaryTransform: + return getTypeInfo(cast(T)->getUnderlyingType()); + case Type::Elaborated: return getTypeInfo(cast(T)->getNamedType().getTypePtr()); @@ -1605,6 +1608,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const { case Type::TypeOfExpr: case Type::TypeOf: case Type::Decltype: + case Type::UnaryTransform: case Type::DependentName: case Type::InjectedClassName: case Type::TemplateSpecialization: @@ -2802,6 +2806,20 @@ QualType ASTContext::getDecltypeType(Expr *e) const { 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 *Ty = + new UnaryTransformType (BaseType, UnderlyingType, Kind, + UnderlyingType->isDependentType() ? + QualType() : UnderlyingType); + Types.push_back(Ty); + return QualType(Ty, 0); +} + /// getAutoType - We only unique auto types after they've been deduced. QualType ASTContext::getAutoType(QualType DeducedType) const { void *InsertPos = 0; diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index dc881ba869..8904a9561c 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -64,6 +64,7 @@ namespace { // FIXME: DependentTypeOfExprType QualType VisitTypeOfType(const TypeOfType *T); QualType VisitDecltypeType(const DecltypeType *T); + QualType VisitUnaryTransformType(const UnaryTransformType *T); QualType VisitAutoType(const AutoType *T); // FIXME: DependentDecltypeType QualType VisitRecordType(const RecordType *T); @@ -604,7 +605,14 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, cast(T2)->getUnderlyingType())) return false; break; - + + case Type::UnaryTransform: + if (!IsStructurallyEquivalent(Context, + cast(T1)->getUnderlyingType(), + cast(T1)->getUnderlyingType())) + return false; + break; + case Type::Decltype: if (!IsStructurallyEquivalent(Context, cast(T1)->getUnderlyingExpr(), @@ -1572,6 +1580,17 @@ QualType ASTNodeImporter::VisitDecltypeType(const DecltypeType *T) { return Importer.getToContext().getDecltypeType(ToExpr); } +QualType ASTNodeImporter::VisitUnaryTransformType(const UnaryTransformType *T) { + QualType ToBaseType = Importer.Import(T->getBaseType()); + QualType ToUnderlyingType = Importer.Import(T->getUnderlyingType()); + if (ToBaseType.isNull() || ToUnderlyingType.isNull()) + return QualType(); + + return Importer.getToContext().getUnaryTransformType(ToBaseType, + ToUnderlyingType, + T->getUTTKind()); +} + QualType ASTNodeImporter::VisitAutoType(const AutoType *T) { // FIXME: Make sure that the "to" context supports C++0x! QualType FromDeduced = T->getDeducedType(); diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index e368c8927f..aad6e9c48d 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -1939,6 +1939,22 @@ void CXXNameMangler::mangleType(const DecltypeType *T) { 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; + } + } + + mangleType(T->getUnderlyingType()); +} + void CXXNameMangler::mangleType(const AutoType *T) { QualType D = T->getDeducedType(); // ::= Da # dependent auto diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp index 5424bebc81..4f920f9aac 100644 --- a/lib/AST/MicrosoftMangle.cpp +++ b/lib/AST/MicrosoftMangle.cpp @@ -1113,6 +1113,10 @@ void MicrosoftCXXNameMangler::mangleType(const DecltypeType *T) { assert(false && "Don't know how to mangle DecltypeTypes yet!"); } +void MicrosoftCXXNameMangler::mangleType(const UnaryTransformType *T) { + assert(false && "Don't know how to mangle UnaryTransformationTypes yet!"); +} + void MicrosoftCXXNameMangler::mangleType(const AutoType *T) { assert(false && "Don't know how to mangle AutoTypes yet!"); } diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 9f576db535..d287552844 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -1535,6 +1535,16 @@ static TagDecl *getInterestingTagDecl(TagDecl *decl) { return decl; } +UnaryTransformType::UnaryTransformType(QualType BaseType, + QualType UnderlyingType, + UTTKind UKind, + QualType CanonicalType) + : Type(UnaryTransform, CanonicalType, UnderlyingType->isDependentType(), + UnderlyingType->isVariablyModifiedType(), + BaseType->containsUnexpandedParameterPack()) + , BaseType(BaseType), UnderlyingType(UnderlyingType), UKind(UKind) +{} + TagDecl *TagType::getDecl() const { return getInterestingTagDecl(decl); } diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 0c5df7fae6..aad97fb9fc 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -94,6 +94,7 @@ void TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) { case Type::TypeOfExpr: case Type::TypeOf: case Type::Decltype: + case Type::UnaryTransform: case Type::Record: case Type::Enum: case Type::Elaborated: @@ -512,6 +513,20 @@ void TypePrinter::printDecltype(const DecltypeType *T, std::string &S) { S = "decltype(" + s.str() + ")" + S; } +void TypePrinter::printUnaryTransform(const UnaryTransformType *T, + std::string &S) { + if (!S.empty()) + S = ' ' + S; + std::string Str; + print(T->getBaseType(), Str); + + switch (T->getUTTKind()) { + case UnaryTransformType::EnumUnderlyingType: + S = "__underlying_type(" + Str + ")" + S; + break; + } +} + void TypePrinter::printAuto(const AutoType *T, std::string &S) { // If the type has been deduced, do not print 'auto'. if (T->isDeduced()) { diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 1c9d91a2e3..6c73865c3c 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -1444,6 +1444,9 @@ static QualType UnwrapTypeForDebugInfo(QualType T) { case Type::Decltype: T = cast(T)->getUnderlyingType(); break; + case Type::UnaryTransform: + T = cast(T)->getUnderlyingType(); + break; case Type::Attributed: T = cast(T)->getEquivalentType(); break; @@ -1559,6 +1562,7 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, case Type::TypeOfExpr: case Type::TypeOf: case Type::Decltype: + case Type::UnaryTransform: case Type::Auto: llvm_unreachable("type should have been unwrapped!"); return llvm::DIType(); diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index f623c8e5b6..d3b34b922d 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -603,7 +603,7 @@ void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) { const char *PrevSpec = 0; unsigned DiagID; - if (DS.SetTypeSpecType(DeclSpec::TST_underlying_type, StartLoc, PrevSpec, + if (DS.SetTypeSpecType(DeclSpec::TST_underlyingType, StartLoc, PrevSpec, DiagID, Result.release())) Diag(StartLoc, DiagID) << PrevSpec; } diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp index d6f8f91bbf..5be16e7431 100644 --- a/lib/Sema/DeclSpec.cpp +++ b/lib/Sema/DeclSpec.cpp @@ -309,7 +309,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) { case DeclSpec::TST_typeofExpr: return "typeof"; case DeclSpec::TST_auto: return "auto"; case DeclSpec::TST_decltype: return "(decltype)"; - case DeclSpec::TST_underlying_type: return "__underlying_type"; + case DeclSpec::TST_underlyingType: return "__underlying_type"; case DeclSpec::TST_unknown_anytype: return "__unknown_anytype"; case DeclSpec::TST_error: return "(error)"; } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 7bcd205b22..41e05d5cdb 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2865,7 +2865,7 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D, case DeclSpec::TST_typename: case DeclSpec::TST_typeofType: case DeclSpec::TST_decltype: - case DeclSpec::TST_underlying_type: { + case DeclSpec::TST_underlyingType: { // Grab the type from the parser. TypeSourceInfo *TSI = 0; QualType T = S.GetTypeFromParser(DS.getRepAsType(), &TSI); diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 8e7e1a12dd..d978c389b2 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -3106,6 +3106,11 @@ bool UnnamedLocalNoLinkageFinder::VisitDecltypeType(const DecltypeType*) { return false; } +bool UnnamedLocalNoLinkageFinder::VisitUnaryTransformType( + const UnaryTransformType*) { + return false; +} + bool UnnamedLocalNoLinkageFinder::VisitAutoType(const AutoType *T) { return Visit(T->getDeducedType()); } diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index f2ec09b132..c4627eb1e3 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -3886,6 +3886,13 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T, OnlyDeduced, Depth, Used); break; + case Type::UnaryTransform: + if (!OnlyDeduced) + MarkUsedTemplateParameters(SemaRef, + cast(T)->getUnderlyingType(), + OnlyDeduced, Depth, Used); + break; + case Type::PackExpansion: MarkUsedTemplateParameters(SemaRef, cast(T)->getPattern(), diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp index 100c6a77a0..86d3bc1709 100644 --- a/lib/Sema/SemaTemplateVariadic.cpp +++ b/lib/Sema/SemaTemplateVariadic.cpp @@ -618,7 +618,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) { switch (DS.getTypeSpecType()) { case TST_typename: case TST_typeofType: - case TST_underlying_type: { + case TST_underlyingType: { QualType T = DS.getRepAsType().get(); if (!T.isNull() && T->containsUnexpandedParameterPack()) return true; diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 884144f99b..a2433cad51 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -836,26 +836,15 @@ static QualType ConvertDeclSpecToType(Sema &S, TypeProcessingState &state) { } break; } - case DeclSpec::TST_underlying_type: - // FIXME: Preserve type source info? + case DeclSpec::TST_underlyingType: Result = S.GetTypeFromParser(DS.getRepAsType()); assert(!Result.isNull() && "Didn't get a type for __underlying_type?"); - if (!Result->isDependentType()) { - if (Result->isEnumeralType()) { - EnumDecl *ED = Result->getAs()->getDecl(); - S.DiagnoseUseOfDecl(ED, DS.getTypeSpecTypeLoc()); - QualType UnderlyingType = ED->getIntegerType(); - if (UnderlyingType.isNull()) { - declarator.setInvalidType(true); - Result = Context.IntTy; - } else { - Result = UnderlyingType; - } - } else { - S.Diag(DS.getTypeSpecTypeLoc(), - diag::err_only_enums_have_underlying_types); - Result = Context.IntTy; - } + Result = S.BuildUnaryTransformType(Result, + UnaryTransformType::EnumUnderlyingType, + DS.getTypeSpecTypeLoc()); + if (Result.isNull()) { + Result = Context.IntTy; + declarator.setInvalidType(true); } break; @@ -2397,6 +2386,16 @@ namespace { Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo); TL.setUnderlyingTInfo(TInfo); } + void VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) { + // FIXME: This holds only because we only have one unary transform. + assert(DS.getTypeSpecType() == DeclSpec::TST_underlyingType); + TL.setKWLoc(DS.getTypeSpecTypeLoc()); + TL.setParensRange(DS.getTypeofParensRange()); + assert(DS.getRepAsType()); + TypeSourceInfo *TInfo = 0; + Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo); + TL.setUnderlyingTInfo(TInfo); + } void VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { // By default, use the source location of the type specifier. TL.setBuiltinLoc(DS.getTypeSpecTypeLoc()); @@ -3397,3 +3396,27 @@ QualType Sema::BuildDecltypeType(Expr *E, SourceLocation Loc) { return Context.getDecltypeType(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()) { + EnumDecl *ED = BaseType->getAs()->getDecl(); + assert(ED && "EnumType has no EnumDecl"); + DiagnoseUseOfDecl(ED, Loc); + Underlying = ED->getIntegerType(); + } + assert(!Underlying.isNull()); + return Context.getUnaryTransformType(BaseType, Underlying, + UnaryTransformType::EnumUnderlyingType); + } + } + llvm_unreachable("unknown unary transform type"); +} diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index db65e2ba30..396a978260 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -702,6 +702,11 @@ public: /// 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, + SourceLocation Loc); + /// \brief Build a new C++0x decltype type. /// /// By default, performs semantic analysis when building the decltype type. @@ -4158,6 +4163,29 @@ QualType TreeTransform::TransformDecltypeType(TypeLocBuilder &TLB, return Result; } +template +QualType TreeTransform::TransformUnaryTransformType( + TypeLocBuilder &TLB, + UnaryTransformTypeLoc TL) { + 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(), + TL.getKWLoc()); + if (Result.isNull()) + return QualType(); + } + + UnaryTransformTypeLoc NewTL = TLB.push(Result); + NewTL.setKWLoc(TL.getKWLoc()); + NewTL.setParensRange(TL.getParensRange()); + NewTL.setUnderlyingTInfo(TL.getUnderlyingTInfo()); + return Result; +} + template QualType TreeTransform::TransformAutoType(TypeLocBuilder &TLB, AutoTypeLoc TL) { @@ -8052,6 +8080,13 @@ QualType TreeTransform::RebuildDecltypeType(Expr *E, 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::RebuildTemplateSpecializationType( TemplateName Template, diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 0ab1704b11..240df2cde8 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -3199,6 +3199,13 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) { case TYPE_DECLTYPE: return Context->getDecltypeType(ReadExpr(*Loc.F)); + case TYPE_UNARY_TRANSFORM: { + QualType BaseType = GetType(Record[0]); + QualType UnderlyingType = GetType(Record[1]); + UnaryTransformType::UTTKind UKind = (UnaryTransformType::UTTKind)Record[2]; + return Context->getUnaryTransformType(BaseType, UnderlyingType, UKind); + } + case TYPE_AUTO: return Context->getAutoType(GetType(Record[0])); @@ -3515,6 +3522,12 @@ void TypeLocReader::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { void TypeLocReader::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) { TL.setNameLoc(ReadSourceLocation(Record, Idx)); } +void TypeLocReader::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) { + TL.setKWLoc(ReadSourceLocation(Record, Idx)); + TL.setLParenLoc(ReadSourceLocation(Record, Idx)); + TL.setRParenLoc(ReadSourceLocation(Record, Idx)); + TL.setUnderlyingTInfo(Reader.GetTypeSourceInfo(F, Record, Idx)); +} void TypeLocReader::VisitAutoTypeLoc(AutoTypeLoc TL) { TL.setNameLoc(ReadSourceLocation(Record, Idx)); } diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 9682dfda12..297115c491 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -223,6 +223,13 @@ void ASTTypeWriter::VisitDecltypeType(const DecltypeType *T) { Code = TYPE_DECLTYPE; } +void ASTTypeWriter::VisitUnaryTransformType(const UnaryTransformType *T) { + Writer.AddTypeRef(T->getBaseType(), Record); + Writer.AddTypeRef(T->getUnderlyingType(), Record); + Record.push_back(T->getUTTKind()); + Code = TYPE_UNARY_TRANSFORM; +} + void ASTTypeWriter::VisitAutoType(const AutoType *T) { Writer.AddTypeRef(T->getDeducedType(), Record); Code = TYPE_AUTO; @@ -494,6 +501,12 @@ void TypeLocWriter::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { void TypeLocWriter::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } +void TypeLocWriter::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) { + Writer.AddSourceLocation(TL.getKWLoc(), Record); + Writer.AddSourceLocation(TL.getLParenLoc(), Record); + Writer.AddSourceLocation(TL.getRParenLoc(), Record); + Writer.AddTypeSourceInfo(TL.getUnderlyingTInfo(), Record); +} void TypeLocWriter::VisitAutoTypeLoc(AutoTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } diff --git a/test/SemaCXX/underlying_type.cpp b/test/SemaCXX/underlying_type.cpp index 0e43100cb8..607d9ad843 100644 --- a/test/SemaCXX/underlying_type.cpp +++ b/test/SemaCXX/underlying_type.cpp @@ -25,3 +25,13 @@ static_assert(is_same_type::value, __underlying_type(f) h; static_assert(is_same_type::value, "h has the wrong type"); + +template +struct underlying_type { + typedef __underlying_type(T) type; // expected-error {{only enumeration types}} +}; + +static_assert(is_same_type::type, char>::value, + "f has the wrong underlying type in the template"); + +underlying_type::type e; // expected-note {{requested here}} diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 00141184c7..7348491072 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -350,6 +350,7 @@ public: bool VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL); bool VisitPackExpansionTypeLoc(PackExpansionTypeLoc TL); bool VisitTypeOfTypeLoc(TypeOfTypeLoc TL); + bool VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL); bool VisitDependentNameTypeLoc(DependentNameTypeLoc TL); bool VisitDependentTemplateSpecializationTypeLoc( DependentTemplateSpecializationTypeLoc TL); @@ -1553,6 +1554,13 @@ bool CursorVisitor::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { return false; } +bool CursorVisitor::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) { + if (TypeSourceInfo *TSInfo = TL.getUnderlyingTInfo()) + return Visit(TSInfo->getTypeLoc()); + + return false; +} + bool CursorVisitor::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) { if (VisitNestedNameSpecifierLoc(TL.getQualifierLoc())) return true;