Add a DecltypeType type.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@74099 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj
index 73ef1be..26be7bb 100644
--- a/clang.xcodeproj/project.pbxproj
+++ b/clang.xcodeproj/project.pbxproj
@@ -694,8 +694,8 @@
 		DEF165220F8D46980098507F /* Util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Util.h; path = clang/Driver/Util.h; sourceTree = "<group>"; };
 		DEF165230F8D46980098507F /* Phases.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Phases.h; path = clang/Driver/Phases.h; sourceTree = "<group>"; };
 		DEF165240F8D46980098507F /* DriverDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DriverDiagnostic.h; path = clang/Driver/DriverDiagnostic.h; sourceTree = "<group>"; };
-		DEF165700F8FB34D0098507F /* PCHWriter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PCHWriter.cpp; path = lib/Frontend/PCHWriter.cpp; sourceTree = "<group>"; };
-		DEF165740F8FB3510098507F /* PCHReader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PCHReader.cpp; path = lib/Frontend/PCHReader.cpp; sourceTree = "<group>"; };
+		DEF165700F8FB34D0098507F /* PCHWriter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = PCHWriter.cpp; path = lib/Frontend/PCHWriter.cpp; sourceTree = "<group>"; tabWidth = 2; };
+		DEF165740F8FB3510098507F /* PCHReader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = PCHReader.cpp; path = lib/Frontend/PCHReader.cpp; sourceTree = "<group>"; tabWidth = 2; };
 		DEF165780F8FB3690098507F /* PCHWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PCHWriter.h; path = clang/Frontend/PCHWriter.h; sourceTree = "<group>"; };
 		DEF1657B0F8FB36E0098507F /* PCHReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PCHReader.h; path = clang/Frontend/PCHReader.h; sourceTree = "<group>"; };
 		DEF1657E0F8FB3730098507F /* PCHBitCodes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PCHBitCodes.h; path = clang/Frontend/PCHBitCodes.h; sourceTree = "<group>"; };
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index b686b0e..2d35b4d 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -360,6 +360,9 @@
   QualType getTypeOfExprType(Expr *e);
   QualType getTypeOfType(QualType t);
   
+  /// getDecltypeType - C++0x decltype.
+  QualType getDecltypeType(Expr *e);
+  
   /// getTagDeclType - Return the unique reference to the type for the
   /// specified TagDecl (struct/union/class/enum) decl.
   QualType getTagDeclType(TagDecl *Decl);
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index ca55ea6..fbbd5c5 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -1358,6 +1358,21 @@
   static bool classof(const TypeOfType *) { return true; }
 };
 
+/// DecltypeType (C++0x)
+class DecltypeType : public Type {
+  Expr *E;
+  DecltypeType(Expr *E, QualType can);
+  friend class ASTContext;  // ASTContext creates these.
+public:
+  Expr *getUnderlyingExpr() const { return E; }
+  
+  virtual void getAsStringInternal(std::string &InnerString, 
+                                   const PrintingPolicy &Policy) const;
+  
+  static bool classof(const Type *T) { return T->getTypeClass() == Decltype; }
+  static bool classof(const DecltypeType *) { return true; }
+};
+  
 class TagType : public Type {
   /// Stores the TagDecl associated with this type. The decl will
   /// point to the TagDecl that actually defines the entity (or is a
diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def
index 5555a9b..64a09d8 100644
--- a/include/clang/AST/TypeNodes.def
+++ b/include/clang/AST/TypeNodes.def
@@ -69,6 +69,7 @@
 NON_CANONICAL_TYPE(Typedef, Type)
 NON_CANONICAL_TYPE(TypeOfExpr, Type)
 NON_CANONICAL_TYPE(TypeOf, Type)
+NON_CANONICAL_TYPE(Decltype, Type)
 ABSTRACT_TYPE(Tag, Type)
 TYPE(Record, TagType)
 TYPE(Enum, TagType)
diff --git a/include/clang/Frontend/PCHBitCodes.h b/include/clang/Frontend/PCHBitCodes.h
index e546a12..6322272 100644
--- a/include/clang/Frontend/PCHBitCodes.h
+++ b/include/clang/Frontend/PCHBitCodes.h
@@ -387,7 +387,9 @@
       /// \brief An ObjCQualifiedInterfaceType record.
       TYPE_OBJC_QUALIFIED_INTERFACE = 22,
       /// \brief An ObjCObjectPointerType record.
-      TYPE_OBJC_OBJECT_POINTER      = 23
+      TYPE_OBJC_OBJECT_POINTER      = 23,
+      /// \brief a DecltypeType record.
+      TYPE_DECLTYPE                 = 24
     };
 
     /// \brief The type IDs for special types constructed by semantic
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index b80142f..e23bb34 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -460,6 +460,10 @@
   case Type::TypeOf:
     return getTypeInfo(cast<TypeOfType>(T)->getUnderlyingType().getTypePtr());
 
+  case Type::Decltype:
+    return getTypeInfo(cast<DecltypeType>(T)->getUnderlyingExpr()->getType()
+                        .getTypePtr());
+
   case Type::QualifiedName:
     return getTypeInfo(cast<QualifiedNameType>(T)->getNamedType().getTypePtr());
     
@@ -1659,6 +1663,19 @@
   return QualType(tot, 0);
 }
 
+/// getDecltypeType -  Unlike many "get<Type>" functions, we don't unique
+/// DecltypeType AST's. The only motivation to unique these nodes would be
+/// memory savings. Since decltype(t) is fairly uncommon, space shouldn't be
+/// an issue. This doesn't effect the type checker, since it operates 
+/// on canonical type's (which are always unique).
+QualType ASTContext::getDecltypeType(Expr *e) {
+  // FIXME: Use the right type here!
+  QualType Canonical = getCanonicalType(e->getType());
+  DecltypeType *dt = new (*this, 8) DecltypeType(e, Canonical);
+  Types.push_back(dt);
+  return QualType(dt, 0);
+}
+
 /// getTagDeclType - Return the unique reference to the type for the
 /// specified TagDecl (struct/union/class/enum) decl.
 QualType ASTContext::getTagDeclType(TagDecl *Decl) {
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 7b45b21..9894adf 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -1052,6 +1052,11 @@
   assert(!isa<TypedefType>(can) && "Invalid canonical type");
 }
 
+DecltypeType::DecltypeType(Expr *E, QualType can)
+  : Type(Decltype, can, E->isTypeDependent()), E(E) {
+  assert(!isa<TypedefType>(can) && "Invalid canonical type");
+}
+
 TagType::TagType(TypeClass TC, TagDecl *D, QualType can) 
   : Type(TC, can, D->isDependentType()), decl(D, 0) {}
 
@@ -1421,6 +1426,16 @@
   InnerString = "typeof(" + Tmp + ")" + InnerString;
 }
 
+void DecltypeType::getAsStringInternal(std::string &InnerString, 
+                                       const PrintingPolicy &Policy) const {
+  if (!InnerString.empty())    // Prefix the basic type, e.g. 'decltype(t) X'.
+    InnerString = ' ' + InnerString;
+  std::string Str;
+  llvm::raw_string_ostream s(Str);
+  getUnderlyingExpr()->printPretty(s, 0, Policy);
+  InnerString = "decltype(" + s.str() + ")" + InnerString;
+}
+
 void FunctionNoProtoType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
   // If needed for precedence reasons, wrap the inner part in grouping parens.
   if (!S.empty())
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index a2b8d13..fb1fefe 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -810,6 +810,9 @@
   case Type::TypeOf:
     return Slot = getOrCreateType(cast<TypeOfType>(Ty)->getUnderlyingType(),
                                   Unit);
+  case Type::Decltype:
+    return Slot = getOrCreateType(cast<DecltypeType>(Ty)->getUnderlyingExpr()
+                                  ->getType(), Unit);
   }
   
   return Slot;
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp
index 96f21f1..0ee0c90 100644
--- a/lib/Frontend/PCHReader.cpp
+++ b/lib/Frontend/PCHReader.cpp
@@ -1822,7 +1822,10 @@
     QualType UnderlyingType = GetType(Record[0]);
     return Context->getTypeOfType(UnderlyingType);
   }
-    
+   
+  case pch::TYPE_DECLTYPE:
+    return Context->getDecltypeType(ReadTypeExpr());
+
   case pch::TYPE_RECORD:
     assert(Record.size() == 1 && "incorrect encoding of record type");
     return Context->getTypeDeclType(cast<RecordDecl>(GetDecl(Record[0])));
diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp
index 3b1eb08..d1f9b97 100644
--- a/lib/Frontend/PCHWriter.cpp
+++ b/lib/Frontend/PCHWriter.cpp
@@ -185,6 +185,11 @@
   Code = pch::TYPE_TYPEOF;
 }
 
+void PCHTypeWriter::VisitDecltypeType(const DecltypeType *T) {
+  Writer.AddStmt(T->getUnderlyingExpr());
+  Code = pch::TYPE_DECLTYPE;
+}
+
 void PCHTypeWriter::VisitTagType(const TagType *T) {
   Writer.AddDeclRef(T->getDecl(), Record);
   assert(!T->isBeingDefined() && 
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 1c4e907..0f67748 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -546,6 +546,18 @@
   return SemaRef.Context.getTypeOfType(Underlying);
 }
 
+QualType
+TemplateTypeInstantiator::InstantiateDecltypeType(const DecltypeType *T,
+                                                  unsigned Quals) const {
+  Sema::OwningExprResult E 
+    = SemaRef.InstantiateExpr(T->getUnderlyingExpr(), TemplateArgs);
+
+  if (E.isInvalid())
+    return QualType();
+  
+  return SemaRef.Context.getDecltypeType(E.takeAs<Expr>());
+}
+
 QualType 
 TemplateTypeInstantiator::InstantiateRecordType(const RecordType *T,
                                                 unsigned Quals) const {