[cfe-commits] r100054 - in /cfe/trunk: include/clang/AST/Type.h lib/AST/Type.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaTemplate.cpp lib/Sema/TreeTransform.h test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp test/SemaTemplate/instantiate-elab-type-specifier.cpp

Douglas Gregor dgregor at apple.com
Wed Mar 31 15:19:08 PDT 2010


Author: dgregor
Date: Wed Mar 31 17:19:08 2010
New Revision: 100054

URL: http://llvm.org/viewvc/llvm-project?rev=100054&view=rev
Log:
Change the representation of dependent elaborated-type-specifiers
(such as "class T::foo") from an ElaboratedType of a TypenameType to a
DependentNameType, which more accurately models the underlying
concept.

Improve template instantiation for DependentNameType nodes that
represent nested-name-specifiers, by performing tag name lookup and
checking the resulting tag appropriately. Fixes PR5681.

There is still much testing and cleanup to do in this area.


Added:
    cfe/trunk/test/SemaTemplate/instantiate-elab-type-specifier.cpp
Modified:
    cfe/trunk/include/clang/AST/Type.h
    cfe/trunk/lib/AST/Type.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/lib/Sema/TreeTransform.h
    cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp

Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=100054&r1=100053&r2=100054&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Wed Mar 31 17:19:08 2010
@@ -894,6 +894,9 @@
   bool isDependentType() const { return Dependent; }
   bool isOverloadableType() const;
 
+  /// \brief Determine wither this type is a C++ elaborated-type-specifier.
+  bool isElaboratedTypeSpecifier() const;
+  
   /// hasPointerRepresentation - Whether this type is represented
   /// natively as a pointer; this includes pointers, references, block
   /// pointers, and Objective-C interface, qualified id, and qualified

Modified: cfe/trunk/lib/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=100054&r1=100053&r2=100054&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Wed Mar 31 17:19:08 2010
@@ -760,6 +760,27 @@
   }
 }
 
+bool Type::isElaboratedTypeSpecifier() const {
+  if (getTypeClass() == Elaborated)
+    return true;
+  
+  if (const DependentNameType *Dependent = dyn_cast<DependentNameType>(this)) {
+    switch (Dependent->getKeyword()) {
+    case ETK_None:
+    case ETK_Typename:
+      return false;
+        
+    case ETK_Class:
+    case ETK_Struct:
+    case ETK_Union:
+    case ETK_Enum:
+      return true;
+    }
+  }
+  
+  return false;
+}
+
 const char *Type::getTypeClassName() const {
   switch (TC) {
   default: assert(0 && "Type class not in TypeNodes.def!");

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=100054&r1=100053&r2=100054&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Mar 31 17:19:08 2010
@@ -5408,7 +5408,7 @@
   //
   // FIXME: handle "template <> friend class A<T>;", which
   // is possibly well-formed?  Who even knows?
-  if (TempParams.size() && !isa<ElaboratedType>(T)) {
+  if (TempParams.size() && !T->isElaboratedTypeSpecifier()) {
     Diag(Loc, diag::err_tagless_friend_type_template)
       << DS.getSourceRange();
     return DeclPtrTy();
@@ -5420,7 +5420,7 @@
   //   * The class-key of the elaborated-type-specifier is required.
   // This is one of the rare places in Clang where it's legitimate to
   // ask about the "spelling" of the type.
-  if (!getLangOptions().CPlusPlus0x && !isa<ElaboratedType>(T)) {
+  if (!getLangOptions().CPlusPlus0x && !T->isElaboratedTypeSpecifier()) {
     // If we evaluated the type to a record type, suggest putting
     // a tag in front.
     if (const RecordType *RT = T->getAs<RecordType>()) {

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=100054&r1=100053&r2=100054&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed Mar 31 17:19:08 2010
@@ -4915,14 +4915,15 @@
   if (!NNS)
     return true;
 
-  QualType T = CheckTypenameType(NNS, *Name, SourceRange(TagLoc, NameLoc));
-  if (T.isNull())
-    return true;
-
-  TagDecl::TagKind TagKind = TagDecl::getTagKindForTypeSpec(TagSpec);
-  QualType ElabType = Context.getElaboratedType(T, TagKind);
-
-  return ElabType.getAsOpaquePtr();
+  ElaboratedTypeKeyword Keyword;
+  switch (TagDecl::getTagKindForTypeSpec(TagSpec)) {
+  case TagDecl::TK_struct: Keyword = ETK_Struct; break;
+  case TagDecl::TK_class: Keyword = ETK_Class; break;
+  case TagDecl::TK_union: Keyword = ETK_Union; break;
+  case TagDecl::TK_enum: Keyword = ETK_Enum; break;
+  }
+  
+  return Context.getDependentNameType(Keyword, NNS, Name).getAsOpaquePtr();
 }
 
 Sema::TypeResult

Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=100054&r1=100053&r2=100054&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Wed Mar 31 17:19:08 2010
@@ -537,19 +537,21 @@
 
   /// \brief Build a new typename type that refers to a template-id.
   ///
-  /// By default, builds a new DependentNameType type from the nested-name-specifier
+  /// 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(ElaboratedTypeKeyword Keyword,
                                     NestedNameSpecifier *NNS, QualType T) {
     if (NNS->isDependent()) {
+      // If the name is still dependent, just build a new dependent name type.
       CXXScopeSpec SS;
       SS.setScopeRep(NNS);
       if (!SemaRef.computeDeclContext(SS))
         return SemaRef.Context.getDependentNameType(Keyword, NNS,
                                           cast<TemplateSpecializationType>(T));
     }
-
+    
     // FIXME: Handle elaborated-type-specifiers separately.
     return SemaRef.Context.getQualifiedNameType(NNS, T);
   }
@@ -563,8 +565,76 @@
                                     NestedNameSpecifier *NNS,
                                     const IdentifierInfo *Id,
                                     SourceRange SR) {
-    // FIXME: Handle elaborated-type-specifiers separately.
-    return SemaRef.CheckTypenameType(NNS, *Id, SR);
+    CXXScopeSpec SS;
+    SS.setScopeRep(NNS);
+    
+    if (NNS->isDependent()) {
+      // If the name is still dependent, just build a new dependent name type.
+      if (!SemaRef.computeDeclContext(SS))
+        return SemaRef.Context.getDependentNameType(Keyword, NNS, Id);
+    }
+
+    TagDecl::TagKind Kind = TagDecl::TK_enum;
+    switch (Keyword) {
+      case ETK_None:
+        // FIXME: Note the lack of the "typename" specifier!
+        // Fall through
+      case ETK_Typename:
+        return SemaRef.CheckTypenameType(NNS, *Id, SR);
+        
+      case ETK_Class: Kind = TagDecl::TK_class; break;
+      case ETK_Struct: Kind = TagDecl::TK_struct; break;
+      case ETK_Union: Kind = TagDecl::TK_union; break;
+      case ETK_Enum: Kind = TagDecl::TK_enum; break;
+    }
+    
+    // We had a dependent elaborated-type-specifier that as been transformed
+    // into a non-dependent elaborated-type-specifier. Find the tag we're
+    // referring to.
+    LookupResult Result(SemaRef, Id, SR.getEnd(), Sema::LookupTagName);
+    DeclContext *DC = SemaRef.computeDeclContext(SS, false);
+    if (!DC)
+      return QualType();
+
+    TagDecl *Tag = 0;
+    SemaRef.LookupQualifiedName(Result, DC);
+    switch (Result.getResultKind()) {
+      case LookupResult::NotFound:
+      case LookupResult::NotFoundInCurrentInstantiation:
+        break;
+        
+      case LookupResult::Found:
+        Tag = Result.getAsSingle<TagDecl>();
+        break;
+        
+      case LookupResult::FoundOverloaded:
+      case LookupResult::FoundUnresolvedValue:
+        llvm_unreachable("Tag lookup cannot find non-tags");
+        return QualType();
+        
+      case LookupResult::Ambiguous:
+        // Let the LookupResult structure handle ambiguities.
+        return QualType();
+    }
+
+    if (!Tag) {
+      // FIXME: Crummy diagnostic
+      SemaRef.Diag(SR.getEnd(), diag::err_not_tag_in_scope)
+        << Id << SR;
+      return QualType();
+    }
+    
+    // FIXME: Terrible location information
+    if (!SemaRef.isAcceptableTagRedeclaration(Tag, Kind, SR.getEnd(), *Id)) {
+      SemaRef.Diag(SR.getBegin(), diag::err_use_with_wrong_tag) << Id;
+      SemaRef.Diag(Tag->getLocation(), diag::note_previous_use);
+      return QualType();
+    }
+
+    // Build the elaborated-type-specifier type.
+    QualType T = SemaRef.Context.getTypeDeclType(Tag);
+    T = SemaRef.Context.getQualifiedNameType(NNS, T);
+    return SemaRef.Context.getElaboratedType(T, Kind);
   }
 
   /// \brief Build a new nested-name-specifier given the prefix and an

Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp?rev=100054&r1=100053&r2=100054&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp (original)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp Wed Mar 31 17:19:08 2010
@@ -25,8 +25,7 @@
 };
 
 template <> struct B<A> {
-  // FIXME: the error here should be associated with the use at "void foo..."
-  union Member { // expected-note 4 {{previous use is here}} expected-error {{tag type that does not match previous declaration}}
+  union Member { // expected-note 4 {{previous use is here}}
     void* a;
   };
 };
@@ -52,7 +51,8 @@
 void e4(enum B<A>::Member); // expected-error {{use of 'Member' with tag type that does not match previous declaration}}
 
 template <class T> struct C {
-  void foo(class B<T>::Member); // expected-error{{no type named 'Member' in 'B<int>'}}
+  void foo(class B<T>::Member); // expected-error{{'Member' does not name a tag member in the specified scope}} \
+                                // expected-error{{use of 'Member' with tag type that does not match previous declaration}}
 };
 
 C<float> f1;

Added: cfe/trunk/test/SemaTemplate/instantiate-elab-type-specifier.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-elab-type-specifier.cpp?rev=100054&view=auto
==============================================================================
--- cfe/trunk/test/SemaTemplate/instantiate-elab-type-specifier.cpp (added)
+++ cfe/trunk/test/SemaTemplate/instantiate-elab-type-specifier.cpp Wed Mar 31 17:19:08 2010
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// PR5681
+template <class T> struct Base {
+  struct foo {};
+  int foo;
+};
+
+template <class T> struct Derived : Base<T> {
+  typedef struct Base<T>::foo type;
+};
+
+template struct Derived<int>;





More information about the cfe-commits mailing list