]> granicus.if.org Git - clang/commitdiff
Extend DependentNameType with a keyword enum that specifies whether
authorDouglas Gregor <dgregor@apple.com>
Wed, 31 Mar 2010 20:19:30 +0000 (20:19 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 31 Mar 2010 20:19:30 +0000 (20:19 +0000)
this was parsed as a typename-specifier, elaborated-type-specifier
(including the kind), or just a dependent qualified type name.

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

include/clang/AST/ASTContext.h
include/clang/AST/Type.h
lib/AST/ASTContext.cpp
lib/AST/TypePrinter.cpp
lib/CodeGen/Mangle.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaTemplate.cpp
lib/Sema/SemaType.cpp
lib/Sema/TreeTransform.h

index 0bf9642863351b9b5908b185898f302cf4bb5e2a..c41857ec020010420e8a2fa7aa9b1fd52431bd0b 100644 (file)
@@ -630,12 +630,14 @@ public:
 
   QualType getQualifiedNameType(NestedNameSpecifier *NNS,
                                 QualType NamedType);
-  QualType getDependentNameType(NestedNameSpecifier *NNS,
-                           const IdentifierInfo *Name,
-                           QualType Canon = QualType());
-  QualType getDependentNameType(NestedNameSpecifier *NNS,
-                           const TemplateSpecializationType *TemplateId,
-                           QualType Canon = QualType());
+  QualType getDependentNameType(ElaboratedTypeKeyword Keyword,
+                                NestedNameSpecifier *NNS,
+                                const IdentifierInfo *Name,
+                                QualType Canon = QualType());
+  QualType getDependentNameType(ElaboratedTypeKeyword Keyword,
+                                NestedNameSpecifier *NNS,
+                                const TemplateSpecializationType *TemplateId,
+                                QualType Canon = QualType());
   QualType getElaboratedType(QualType UnderlyingType,
                              ElaboratedType::TagKind Tag);
 
index 53346569d31ae8fc81892605a9365dacaab998c4..578382a130e55ca001d6c28b1c292241da70796f 100644 (file)
@@ -2550,6 +2550,24 @@ public:
   static bool classof(const InjectedClassNameType *T) { return true; }
 };
 
+/// \brief The elaboration keyword that precedes a qualified type name or
+/// introduces an elaborated-type-specifier.
+enum ElaboratedTypeKeyword {
+  /// \brief No keyword precedes the qualified type name.
+  ETK_None,
+  /// \brief The "typename" keyword precedes the qualified type name, e.g.,
+  /// \c typename T::type.
+  ETK_Typename,
+  /// \brief The "class" keyword introduces the elaborated-type-specifier.
+  ETK_Class,
+  /// \brief The "struct" keyword introduces the elaborated-type-specifier.
+  ETK_Struct,
+  /// \brief The "union" keyword introduces the elaborated-type-specifier.
+  ETK_Union,
+  /// \brief The "enum" keyword introduces the elaborated-type-specifier.
+  ETK_Enum
+};
+  
 /// \brief Represents a type that was referred to via a qualified
 /// name, e.g., N::M::type.
 ///
@@ -2600,19 +2618,19 @@ public:
   static bool classof(const QualifiedNameType *T) { return true; }
 };
 
-/// \brief Represents a 'typename' specifier that names a type within
-/// a dependent type, e.g., "typename T::type".
+/// \brief Represents a qualified type name for which the type name is
+/// dependent. 
 ///
-/// DependentNameType has a very similar structure to QualifiedNameType,
-/// which also involves a nested-name-specifier following by a type,
-/// and (FIXME!) both can even be prefixed by the 'typename'
-/// keyword. However, the two types serve very different roles:
-/// QualifiedNameType is a non-semantic type that serves only as sugar
-/// to show how a particular type was written in the source
-/// code. DependentNameType, on the other hand, only occurs when the
-/// nested-name-specifier is dependent, such that we cannot resolve
-/// the actual type until after instantiation.
+/// DependentNameType represents a class of dependent types that involve a 
+/// dependent nested-name-specifier (e.g., "T::") followed by a (dependent) 
+/// name of a type. The DependentNameType may start with a "typename" (for a
+/// typename-specifier), "class", "struct", "union", or "enum" (for a 
+/// dependent elaborated-type-specifier), or nothing (in contexts where we
+/// know that we must be referring to a type, e.g., in a base class specifier).
 class DependentNameType : public Type, public llvm::FoldingSetNode {
+  /// \brief The keyword used to elaborate this type.
+  ElaboratedTypeKeyword Keyword;
+  
   /// \brief The nested name specifier containing the qualifier.
   NestedNameSpecifier *NNS;
 
@@ -2622,16 +2640,18 @@ class DependentNameType : public Type, public llvm::FoldingSetNode {
   /// \brief The type that this typename specifier refers to.
   NameType Name;
 
-  DependentNameType(NestedNameSpecifier *NNS, const IdentifierInfo *Name,
-               QualType CanonType)
-    : Type(DependentName, CanonType, true), NNS(NNS), Name(Name) {
+  DependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, 
+                    const IdentifierInfo *Name, QualType CanonType)
+    : Type(DependentName, CanonType, true), 
+      Keyword(Keyword), NNS(NNS), Name(Name) {
     assert(NNS->isDependent() &&
            "DependentNameType requires a dependent nested-name-specifier");
   }
 
-  DependentNameType(NestedNameSpecifier *NNS, const TemplateSpecializationType *Ty,
-               QualType CanonType)
-    : Type(DependentName, CanonType, true), NNS(NNS), Name(Ty) {
+  DependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS,
+                    const TemplateSpecializationType *Ty, QualType CanonType)
+    : Type(DependentName, CanonType, true), 
+      Keyword(Keyword), NNS(NNS), Name(Ty) {
     assert(NNS->isDependent() &&
            "DependentNameType requires a dependent nested-name-specifier");
   }
@@ -2639,6 +2659,9 @@ class DependentNameType : public Type, public llvm::FoldingSetNode {
   friend class ASTContext;  // ASTContext creates these
 
 public:
+  /// \brief Retrieve the keyword used to elaborate this type.
+  ElaboratedTypeKeyword getKeyword() const { return Keyword; }
+  
   /// \brief Retrieve the qualification on this type.
   NestedNameSpecifier *getQualifier() const { return NNS; }
 
@@ -2662,11 +2685,12 @@ public:
   QualType desugar() const { return QualType(this, 0); }
 
   void Profile(llvm::FoldingSetNodeID &ID) {
-    Profile(ID, NNS, Name);
+    Profile(ID, Keyword, NNS, Name);
   }
 
-  static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS,
-                      NameType Name) {
+  static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword,
+                      NestedNameSpecifier *NNS, NameType Name) {
+    ID.AddInteger(Keyword);
     ID.AddPointer(NNS);
     ID.AddPointer(Name.getOpaqueValue());
   }
index 7fce55b9dfda8d4f8a5cef0901872c96c9eeeda6..31c4370ad33414416dde0fac59d5ce72d8c2c9c6 100644 (file)
@@ -1962,19 +1962,24 @@ ASTContext::getQualifiedNameType(NestedNameSpecifier *NNS,
   return QualType(T, 0);
 }
 
-QualType ASTContext::getDependentNameType(NestedNameSpecifier *NNS,
-                                     const IdentifierInfo *Name,
-                                     QualType Canon) {
+QualType ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword,
+                                          NestedNameSpecifier *NNS,
+                                          const IdentifierInfo *Name,
+                                          QualType Canon) {
   assert(NNS->isDependent() && "nested-name-specifier must be dependent");
 
   if (Canon.isNull()) {
     NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS);
-    if (CanonNNS != NNS)
-      Canon = getDependentNameType(CanonNNS, Name);
+    ElaboratedTypeKeyword CanonKeyword = Keyword;
+    if (Keyword == ETK_None)
+      CanonKeyword = ETK_Typename;
+    
+    if (CanonNNS != NNS || CanonKeyword != Keyword)
+      Canon = getDependentNameType(CanonKeyword, CanonNNS, Name);
   }
 
   llvm::FoldingSetNodeID ID;
-  DependentNameType::Profile(ID, NNS, Name);
+  DependentNameType::Profile(ID, Keyword, NNS, Name);
 
   void *InsertPos = 0;
   DependentNameType *T
@@ -1982,20 +1987,21 @@ QualType ASTContext::getDependentNameType(NestedNameSpecifier *NNS,
   if (T)
     return QualType(T, 0);
 
-  T = new (*this) DependentNameType(NNS, Name, Canon);
+  T = new (*this) DependentNameType(Keyword, NNS, Name, Canon);
   Types.push_back(T);
   DependentNameTypes.InsertNode(T, InsertPos);
   return QualType(T, 0);
 }
 
 QualType
-ASTContext::getDependentNameType(NestedNameSpecifier *NNS,
-                            const TemplateSpecializationType *TemplateId,
-                            QualType Canon) {
+ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword,
+                                 NestedNameSpecifier *NNS,
+                                 const TemplateSpecializationType *TemplateId,
+                                 QualType Canon) {
   assert(NNS->isDependent() && "nested-name-specifier must be dependent");
 
   llvm::FoldingSetNodeID ID;
-  DependentNameType::Profile(ID, NNS, TemplateId);
+  DependentNameType::Profile(ID, Keyword, NNS, TemplateId);
 
   void *InsertPos = 0;
   DependentNameType *T
@@ -2006,12 +2012,16 @@ ASTContext::getDependentNameType(NestedNameSpecifier *NNS,
   if (Canon.isNull()) {
     NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS);
     QualType CanonType = getCanonicalType(QualType(TemplateId, 0));
-    if (CanonNNS != NNS || CanonType != QualType(TemplateId, 0)) {
+    ElaboratedTypeKeyword CanonKeyword = Keyword;
+    if (Keyword == ETK_None)
+      CanonKeyword = ETK_Typename;
+    if (CanonNNS != NNS || CanonKeyword != Keyword ||
+        CanonType != QualType(TemplateId, 0)) {
       const TemplateSpecializationType *CanonTemplateId
         = CanonType->getAs<TemplateSpecializationType>();
       assert(CanonTemplateId &&
              "Canonical type must also be a template specialization type");
-      Canon = getDependentNameType(CanonNNS, CanonTemplateId);
+      Canon = getDependentNameType(CanonKeyword, CanonNNS, CanonTemplateId);
     }
 
     DependentNameType *CheckT
@@ -2019,7 +2029,7 @@ ASTContext::getDependentNameType(NestedNameSpecifier *NNS,
     assert(!CheckT && "Typename canonical type is broken"); (void)CheckT;
   }
 
-  T = new (*this) DependentNameType(NNS, TemplateId, Canon);
+  T = new (*this) DependentNameType(Keyword, NNS, TemplateId, Canon);
   Types.push_back(T);
   DependentNameTypes.InsertNode(T, InsertPos);
   return QualType(T, 0);
index da0ac3f5ae9ac4b37e596df7146aae6c15dd04a5..4cf0922ee316487060f762400c8c8658d908d25f 100644 (file)
@@ -572,7 +572,15 @@ void TypePrinter::PrintDependentName(const DependentNameType *T, std::string &S)
   
   {
     llvm::raw_string_ostream OS(MyString);
-    OS << "typename ";
+    switch (T->getKeyword()) {
+    case ETK_None: break;
+    case ETK_Typename: OS << "typename "; break;
+    case ETK_Class: OS << "class "; break;
+    case ETK_Struct: OS << "struct "; break;
+    case ETK_Union: OS << "union "; break;
+    case ETK_Enum: OS << "enum "; break;
+    }
+    
     T->getQualifier()->print(OS, Policy);
     
     if (const IdentifierInfo *Ident = T->getIdentifier())
index af5e5d3c783c04a2d9362f7341581685065710d0..077db7c268524ac99e03fbeca07b8d42fb90b8cf 100644 (file)
@@ -1456,8 +1456,9 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
     // It isn't clear that we ever actually want to have such a
     // nested-name-specifier; why not just represent it as a typename type?
     if (!QTy && NNS->getAsIdentifier() && NNS->getPrefix()) {
-      QTy = getASTContext().getDependentNameType(NNS->getPrefix(),
-                                            NNS->getAsIdentifier())
+      QTy = getASTContext().getDependentNameType(ETK_Typename,
+                                                 NNS->getPrefix(),
+                                                 NNS->getAsIdentifier())
               .getTypePtr();
     }
     assert(QTy && "Qualifier was not type!");
index 4898387357d87fdbcd90a0bbb2df7cb6c427d175..eef73d8d7f5b127f75a365db17f51749fbf6ec1b 100644 (file)
@@ -198,7 +198,9 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
   } else if (UnresolvedUsingTypenameDecl *UUDecl =
                dyn_cast<UnresolvedUsingTypenameDecl>(IIDecl)) {
     // FIXME: preserve source structure information.
-    T = Context.getDependentNameType(UUDecl->getTargetNestedNameSpecifier(), &II);
+    T = Context.getDependentNameType(ETK_None, 
+                                     UUDecl->getTargetNestedNameSpecifier(), 
+                                     &II);
   } else {
     // If it's not plausibly a type, suppress diagnostics.
     Result.suppressDiagnostics();
index 5933659f6d7ee76d95cf62d5c97b5bd5003e7aa2..e3533905fd34de8cbf4adb69a035418f8245427d 100644 (file)
@@ -4958,7 +4958,8 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
     return Context.getQualifiedNameType(NNS, T).getAsOpaquePtr();
   }
 
-  return Context.getDependentNameType(NNS, TemplateId).getAsOpaquePtr();
+  return Context.getDependentNameType(ETK_Typename, NNS, TemplateId)
+                                                            .getAsOpaquePtr();
 }
 
 /// \brief Build the type that describes a C++ typename specifier,
@@ -4973,7 +4974,7 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II,
     // If the nested-name-specifier does not refer to the current
     // instantiation, then build a typename type.
     if (!CurrentInstantiation)
-      return Context.getDependentNameType(NNS, &II);
+      return Context.getDependentNameType(ETK_Typename, NNS, &II);
 
     // The nested-name-specifier refers to the current instantiation, so the
     // "typename" keyword itself is superfluous. In C++03, the program is
@@ -5009,7 +5010,7 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II,
       
   case LookupResult::NotFoundInCurrentInstantiation:
     // Okay, it's a member of an unknown instantiation.
-    return Context.getDependentNameType(NNS, &II);
+    return Context.getDependentNameType(ETK_Typename, NNS, &II);
 
   case LookupResult::Found:
     if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getFoundDecl())) {
@@ -5135,10 +5136,12 @@ CurrentInstantiationRebuilder::TransformDependentNameType(TypeLocBuilder &TLB,
         NewTemplateId == QualType(TemplateId, 0))
       Result = QualType(T, 0);
     else
-      Result = getDerived().RebuildDependentNameType(NNS, NewTemplateId);
+      Result = getDerived().RebuildDependentNameType(T->getKeyword(), 
+                                                     NNS, NewTemplateId);
   } else
-    Result = getDerived().RebuildDependentNameType(NNS, T->getIdentifier(),
-                                              SourceRange(TL.getNameLoc()));
+    Result = getDerived().RebuildDependentNameType(T->getKeyword(),
+                                                   NNS, T->getIdentifier(),
+                                                  SourceRange(TL.getNameLoc()));
 
   if (Result.isNull())
     return QualType();
index 24197adb11d45a063a58f391ce17c418b7ee5fce..8278691a4a3bc83325eda1941aa13465b042a9b0 100644 (file)
@@ -1261,7 +1261,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
         NestedNameSpecifier *NNSPrefix = NNS->getPrefix();
         switch (NNS->getKind()) {
         case NestedNameSpecifier::Identifier:
-          ClsType = Context.getDependentNameType(NNSPrefix, NNS->getAsIdentifier());
+          ClsType = Context.getDependentNameType(ETK_None, NNSPrefix, 
+                                                 NNS->getAsIdentifier());
           break;
 
         case NestedNameSpecifier::Namespace:
index 361ab2e78c9af427af45c7f15d5a0bd4e3968bed..a2ace07576c1574f135956dd229dfca3c34b4cbc 100644 (file)
@@ -540,15 +540,17 @@ public:
   /// By default, builds a new DependentNameType type from the nested-name-specifier
   /// and the given type. Subclasses may override this routine to provide
   /// different behavior.
-  QualType RebuildDependentNameType(NestedNameSpecifier *NNS, QualType T) {
+  QualType RebuildDependentNameType(ElaboratedTypeKeyword Keyword,
+                                    NestedNameSpecifier *NNS, QualType T) {
     if (NNS->isDependent()) {
       CXXScopeSpec SS;
       SS.setScopeRep(NNS);
       if (!SemaRef.computeDeclContext(SS))
-        return SemaRef.Context.getDependentNameType(NNS,
+        return SemaRef.Context.getDependentNameType(Keyword, NNS,
                                           cast<TemplateSpecializationType>(T));
     }
 
+    // FIXME: Handle elaborated-type-specifiers separately.
     return SemaRef.Context.getQualifiedNameType(NNS, T);
   }
 
@@ -557,9 +559,11 @@ public:
   /// By default, performs semantic analysis when building the typename type
   /// (or qualified name type). Subclasses may override this routine to provide
   /// different behavior.
-  QualType RebuildDependentNameType(NestedNameSpecifier *NNS,
-                               const IdentifierInfo *Id,
-                               SourceRange SR) {
+  QualType RebuildDependentNameType(ElaboratedTypeKeyword Keyword, 
+                                    NestedNameSpecifier *NNS,
+                                    const IdentifierInfo *Id,
+                                    SourceRange SR) {
+    // FIXME: Handle elaborated-type-specifiers separately.
     return SemaRef.CheckTypenameType(NNS, *Id, SR);
   }
 
@@ -3023,9 +3027,11 @@ QualType TreeTransform<Derived>::TransformDependentNameType(TypeLocBuilder &TLB,
         NewTemplateId == QualType(TemplateId, 0))
       return QualType(T, 0);
 
-    Result = getDerived().RebuildDependentNameType(NNS, NewTemplateId);
+    Result = getDerived().RebuildDependentNameType(T->getKeyword(), NNS, 
+                                                   NewTemplateId);
   } else {
-    Result = getDerived().RebuildDependentNameType(NNS, T->getIdentifier(), SR);
+    Result = getDerived().RebuildDependentNameType(T->getKeyword(), NNS, 
+                                                   T->getIdentifier(), SR);
   }
   if (Result.isNull())
     return QualType();