]> granicus.if.org Git - clang/commitdiff
Basic support for representing elaborated type specifiers
authorJohn McCall <rjmccall@apple.com>
Sat, 5 Sep 2009 00:15:47 +0000 (00:15 +0000)
committerJohn McCall <rjmccall@apple.com>
Sat, 5 Sep 2009 00:15:47 +0000 (00:15 +0000)
directly in the AST.  The current thinking is to create these
only in C++ mode for efficiency.  But for now, they're not being
created at all; patch to follow.

This will let us do things like verify that tags match during
template instantation, as well as signal that an elaborated type
specifier was used for clients that actually care.

Optimally, the TypeLoc hierarchy should be adjusted to carry tag
location information as well.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@81057 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/ASTContext.h
include/clang/AST/Decl.h
include/clang/AST/Type.h
include/clang/AST/TypeNodes.def
include/clang/Frontend/PCHBitCodes.h
lib/AST/ASTContext.cpp
lib/AST/Type.cpp
lib/CodeGen/CGDebugInfo.cpp
lib/Frontend/PCHReader.cpp
lib/Frontend/PCHWriter.cpp
lib/Sema/TreeTransform.h

index 01da133c07c53f324a7ac67c460afabf46ec433b..f9419fb3c28e8b479fc1253ef56d4f5aea7718c6 100644 (file)
@@ -86,6 +86,7 @@ class ASTContext {
   llvm::FoldingSet<TypenameType> TypenameTypes;
   llvm::FoldingSet<ObjCInterfaceType> ObjCInterfaceTypes;
   llvm::FoldingSet<ObjCObjectPointerType> ObjCObjectPointerTypes;
+  llvm::FoldingSet<ElaboratedType> ElaboratedTypes;
   
   llvm::FoldingSet<QualifiedTemplateName> QualifiedTemplateNames;
   llvm::FoldingSet<DependentTemplateName> DependentTemplateNames;
@@ -471,6 +472,8 @@ public:
   QualType getTypenameType(NestedNameSpecifier *NNS, 
                            const TemplateSpecializationType *TemplateId,
                            QualType Canon = QualType());
+  QualType getElaboratedType(QualType UnderlyingType,
+                             ElaboratedType::TagKind Tag);
 
   QualType getObjCInterfaceType(const ObjCInterfaceDecl *Decl,
                                 ObjCProtocolDecl **Protocols = 0, 
index 28456fff9f9285ee9936ef9331e987ea45020444..765d04947ca8debd2c2e4e297d81ceab6e51bca2 100644 (file)
@@ -1267,12 +1267,12 @@ class TypedefDecl;
 class TagDecl 
   : public TypeDecl, public DeclContext, public Redeclarable<TagDecl> {
 public:
-  enum TagKind {
-    TK_struct,
-    TK_union,
-    TK_class,
-    TK_enum
-  };
+  // This is really ugly.
+  typedef ElaboratedType::TagKind TagKind;
+  static const TagKind TK_struct = ElaboratedType::TK_struct;
+  static const TagKind TK_union = ElaboratedType::TK_union;
+  static const TagKind TK_class = ElaboratedType::TK_class;
+  static const TagKind TK_enum = ElaboratedType::TK_enum;
 
 private:
   // FIXME: This can be packed into the bitfields in Decl.
@@ -1354,13 +1354,7 @@ public:
   TagDecl* getDefinition(ASTContext& C) const;
   
   const char *getKindName() const {
-    switch (getTagKind()) {
-    default: assert(0 && "Unknown TagKind!");
-    case TK_struct: return "struct";
-    case TK_union:  return "union";
-    case TK_class:  return "class";
-    case TK_enum:   return "enum";
-    }
+    return ElaboratedType::getNameForTagKind(getTagKind());
   }
 
   /// getTagKindForTypeSpec - Converts a type specifier (DeclSpec::TST)
index 70bafc1dec32cbe272b04a5c7810bc316f6a30cd..f46227d85fa8e9ec00b85b66dd59a35a1d14f265 100644 (file)
@@ -1770,6 +1770,65 @@ public:
   static bool classof(const EnumType *) { return true; }
 };
 
+/// ElaboratedType - A non-canonical type used to represents uses of
+/// elaborated type specifiers in C++.  For example:
+///
+///   void foo(union MyUnion);
+///            ^^^^^^^^^^^^^
+///
+/// At the moment, for efficiency we do not create elaborated types in
+/// C, since outside of typedefs all references to structs would
+/// necessarily be elaborated.
+class ElaboratedType : public Type, public llvm::FoldingSetNode {
+public:
+  enum TagKind {
+    TK_struct,
+    TK_union,
+    TK_class,
+    TK_enum
+  };
+
+private:
+  /// The tag that was used in this elaborated type specifier.
+  TagKind Tag;
+
+  /// The underlying type.
+  QualType UnderlyingType;
+
+  explicit ElaboratedType(QualType Ty, TagKind Tag, QualType Canon)
+    : Type(Elaborated, Canon, Canon->isDependentType()),
+      Tag(Tag), UnderlyingType(Ty) { }
+  friend class ASTContext;   // ASTContext creates these.
+
+public:
+  TagKind getTagKind() const { return Tag; }
+  QualType getUnderlyingType() const { return UnderlyingType; }
+
+  static const char *getNameForTagKind(TagKind Kind) {
+    switch (Kind) {
+    default: assert(0 && "Unknown TagKind!");
+    case TK_struct: return "struct";
+    case TK_union:  return "union";
+    case TK_class:  return "class";
+    case TK_enum:   return "enum";
+    }
+  }
+
+  virtual void getAsStringInternal(std::string &InnerString, 
+                                   const PrintingPolicy &Policy) const;
+
+  void Profile(llvm::FoldingSetNodeID &ID) {
+    Profile(ID, getUnderlyingType(), getTagKind());
+  }
+  static void Profile(llvm::FoldingSetNodeID &ID, QualType T, TagKind Tag) {
+    ID.AddPointer(T.getAsOpaquePtr());
+    ID.AddInteger(Tag);
+  }
+
+  static bool classof(const ElaboratedType*) { return true; }
+  static bool classof(const Type *T) { return T->getTypeClass() == Elaborated; }
+};
+
 class TemplateTypeParmType : public Type, public llvm::FoldingSetNode {
   unsigned Depth : 15;
   unsigned Index : 16;
index a3186634422de06f701ea7cc11f2c74db63a2b5e..f1d3b362ce348512fe6c3f58d1c6aaa4a0a82788 100644 (file)
@@ -75,6 +75,7 @@ NON_CANONICAL_TYPE(Decltype, Type)
 ABSTRACT_TYPE(Tag, Type)
 TYPE(Record, TagType)
 TYPE(Enum, TagType)
+NON_CANONICAL_TYPE(Elaborated, Type)
 DEPENDENT_TYPE(TemplateTypeParm, Type)
 TYPE(TemplateSpecialization, Type)
 NON_CANONICAL_TYPE(QualifiedName, Type)
index fc3fc20d573a857020d2bea3f2f82ca0c56cf02b..92a541ea19c9cc67a6e96708466e2df5b6698411 100644 (file)
@@ -399,7 +399,9 @@ namespace clang {
       /// \brief A ConstantArrayWithExprType record.
       TYPE_CONSTANT_ARRAY_WITH_EXPR = 24,
       /// \brief A ConstantArrayWithoutExprType record.
-      TYPE_CONSTANT_ARRAY_WITHOUT_EXPR = 25
+      TYPE_CONSTANT_ARRAY_WITHOUT_EXPR = 25,
+      /// \brief An ElaboratedType record.
+      TYPE_ELABORATED               = 26
     };
 
     /// \brief The type IDs for special types constructed by semantic
index 1143b305add0e539bf5f3cecff72f2881450aad3..780b1fdc42e02c0c8b64818fbe227e0ef7f95ef8 100644 (file)
@@ -733,6 +733,10 @@ ASTContext::getTypeInfo(const Type *T) {
     break;
   }
 
+  case Type::Elaborated: {
+    return getTypeInfo(cast<ElaboratedType>(T)->getUnderlyingType().getTypePtr());
+  }
+
   case Type::Typedef: {
     const TypedefDecl *Typedef = cast<TypedefType>(T)->getDecl();
     if (const AlignedAttr *Aligned = Typedef->getAttr<AlignedAttr>()) {
@@ -1901,6 +1905,25 @@ ASTContext::getTypenameType(NestedNameSpecifier *NNS,
   return QualType(T, 0);    
 }
 
+QualType
+ASTContext::getElaboratedType(QualType UnderlyingType,
+                              ElaboratedType::TagKind Tag) {
+  llvm::FoldingSetNodeID ID;
+  ElaboratedType::Profile(ID, UnderlyingType, Tag);
+  
+  void *InsertPos = 0;
+  ElaboratedType *T = ElaboratedTypes.FindNodeOrInsertPos(ID, InsertPos);
+  if (T)
+    return QualType(T, 0);
+
+  QualType Canon = getCanonicalType(UnderlyingType);
+
+  T = new (*this) ElaboratedType(UnderlyingType, Tag, Canon);
+  Types.push_back(T);
+  ElaboratedTypes.InsertNode(T, InsertPos);
+  return QualType(T, 0);
+}
+
 /// CmpProtocolNames - Comparison predicate for sorting protocols
 /// alphabetically.
 static bool CmpProtocolNames(const ObjCProtocolDecl *LHS,
index c6ea357fbd2e9b9704abb17ab62e06fcaa1d5320..f4dad13f41605a1d8a25ff3c87ac3a20ad2df40b 100644 (file)
@@ -1674,6 +1674,16 @@ void ObjCObjectPointerType::getAsStringInternal(std::string &InnerString,
   InnerString = ObjCQIString + InnerString;
 }
 
+void ElaboratedType::getAsStringInternal(std::string &InnerString, 
+                                         const PrintingPolicy &Policy) const {
+  std::string TypeStr;
+  PrintingPolicy InnerPolicy(Policy);
+  InnerPolicy.SuppressTagKind = true;
+  UnderlyingType.getAsStringInternal(InnerString, InnerPolicy);
+
+  InnerString = std::string(getNameForTagKind(getTagKind())) + ' ' + InnerString;
+}
+
 void TagType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
   if (Policy.SuppressTag)
     return;
index c4759b965cbff43b3a88aa8804476dccdcaf833b..e53f1fa52545ad090f5732d8fd0e839873ea6472 100644 (file)
@@ -792,6 +792,9 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty,
   case Type::FunctionProto:
   case Type::FunctionNoProto:
     return Slot = CreateType(cast<FunctionType>(Ty), Unit);
+  case Type::Elaborated:
+    return Slot = getOrCreateType(cast<ElaboratedType>(Ty)->getUnderlyingType(),
+                                  Unit);
     
   case Type::ConstantArray:
   case Type::ConstantArrayWithExpr:
index 4fcf026549b1d76871aa48e224d0b894c1afda03..a7e6c0c8f9eef361d385a23ced811c2d47589e30 100644 (file)
@@ -1941,6 +1941,13 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
     assert(Record.size() == 1 && "incorrect encoding of enum type");
     return Context->getTypeDeclType(cast<EnumDecl>(GetDecl(Record[0])));
 
+  case pch::TYPE_ELABORATED: {
+    assert(Record.size() == 2 && "incorrect encoding of elaborated type");
+    unsigned Tag = Record[1];
+    return Context->getElaboratedType(GetType(Record[0]),
+                                      (ElaboratedType::TagKind) Tag);
+  }
+
   case pch::TYPE_OBJC_INTERFACE: {
     unsigned Idx = 0;
     ObjCInterfaceDecl *ItfD = cast<ObjCInterfaceDecl>(GetDecl(Record[Idx++]));
index 4b8847c09887ec9e42ed5a0d0415cd868a58057e..985d99abbe403c26dbcb8d599c63f86bad6fe461 100644 (file)
@@ -225,6 +225,12 @@ void PCHTypeWriter::VisitEnumType(const EnumType *T) {
   Code = pch::TYPE_ENUM;
 }
 
+void PCHTypeWriter::VisitElaboratedType(const ElaboratedType *T) {
+  Writer.AddTypeRef(T->getUnderlyingType(), Record);
+  Record.push_back(T->getTagKind());
+  Code = pch::TYPE_ELABORATED;
+}
+
 void 
 PCHTypeWriter::VisitTemplateSpecializationType(
                                        const TemplateSpecializationType *T) {
index 22e01ab581411711abf44c596256a77ccacd8846..b49ed5487bb9ab1f1d2386a02a6cbf0ffa3b7048 100644 (file)
@@ -441,6 +441,11 @@ public:
   QualType RebuildEnumType(EnumDecl *Enum) {
     return SemaRef.Context.getTypeDeclType(Enum);
   }
+
+  /// \brief Build a new elaborated type.
+  QualType RebuildElaboratedType(QualType T, ElaboratedType::TagKind Tag) {
+    return SemaRef.Context.getElaboratedType(T, Tag);
+  }
   
   /// \brief Build a new typeof(expr) type. 
   ///
@@ -2328,6 +2333,21 @@ QualType TreeTransform<Derived>::TransformEnumType(const EnumType *T) {
   
   return getDerived().RebuildEnumType(Enum);
 }
+
+template <typename Derived>
+QualType TreeTransform<Derived>::TransformElaboratedType(
+                                                    const ElaboratedType *T) {
+  QualType Underlying = getDerived().TransformType(T->getUnderlyingType());
+  if (Underlying.isNull())
+    return QualType();
+  
+  if (!getDerived().AlwaysRebuild() &&
+      Underlying == T->getUnderlyingType())
+    return QualType(T, 0);
+  
+  return getDerived().RebuildElaboratedType(Underlying, T->getTagKind());
+}
+                                                 
   
 template<typename Derived>
 QualType TreeTransform<Derived>::TransformTemplateTypeParmType(