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/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index e664855..f356c90 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -975,6 +975,9 @@
     return getTypeInfo(cast<DecltypeType>(T)->getUnderlyingExpr()->getType()
                         .getTypePtr());
 
+  case Type::UnaryTransform:
+    return getTypeInfo(cast<UnaryTransformType>(T)->getUnderlyingType());
+
   case Type::Elaborated:
     return getTypeInfo(cast<ElaboratedType>(T)->getNamedType().getTypePtr());
 
@@ -1605,6 +1608,7 @@
   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 @@
   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 dc881ba..8904a95 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -64,6 +64,7 @@
     // 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 @@
                                   cast<TypeOfType>(T2)->getUnderlyingType()))
       return false;
     break;
-      
+
+  case Type::UnaryTransform:
+    if (!IsStructurallyEquivalent(Context,
+                             cast<UnaryTransformType>(T1)->getUnderlyingType(),
+                             cast<UnaryTransformType>(T1)->getUnderlyingType()))
+      return false;
+    break;
+
   case Type::Decltype:
     if (!IsStructurallyEquivalent(Context,
                                   cast<DecltypeType>(T1)->getUnderlyingExpr(),
@@ -1572,6 +1580,17 @@
   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 e368c89..aad6e9c 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -1939,6 +1939,22 @@
   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();
   // <builtin-type> ::= Da  # dependent auto
diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp
index 5424beb..4f920f9 100644
--- a/lib/AST/MicrosoftMangle.cpp
+++ b/lib/AST/MicrosoftMangle.cpp
@@ -1113,6 +1113,10 @@
   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 9f576db..d287552 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -1535,6 +1535,16 @@
   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 0c5df7f..aad97fb 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -94,6 +94,7 @@
     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 @@
   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()) {