Implement explicit instantiations of member classes of class templates, e.g.,

  template<typename T>
  struct X {
    struct Inner;
  };

  template struct X<int>::Inner;

This change is larger than it looks because it also fixes some
a problem with nested-name-specifiers and tags. We weren't requiring
the DeclContext associated with the scope specifier of a tag to be
complete. Therefore, when looking for something like "struct
X<int>::Inner", we weren't instantiating X<int>. 

This, naturally, uncovered a problem with member pointers, where we
were requiring the left-hand side of a member pointer access
expression (e.g., x->*) to be a complete type. However, this is wrong:
the semantics of this expression does not require a complete type (EDG
agrees).

Stuart vouched for me. Blame him.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@71756 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 5650396..963c5ad 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -514,10 +514,10 @@
         //
         //   template class Foo<X>
         //
-        // but it is actually a declaration. Most likely, this was
+        // but it actually has a definition. Most likely, this was
         // meant to be an explicit specialization, but the user forgot
         // the '<>' after 'template'.
-        assert(TK == Action::TK_Definition && "Can only get a definition here");
+        assert(TK == Action::TK_Definition && "Expected a definition here");
 
         SourceLocation LAngleLoc 
           = PP.getLocForEndOfToken(TemplateInfo.TemplateLoc);
@@ -554,7 +554,8 @@
                                  TemplateParams? TemplateParams->size() : 0));
     }
     TemplateId->Destroy();
-  } else if (TemplateParams && TK != Action::TK_Reference)
+  } else if (TemplateParams && TK != Action::TK_Reference) {
+    // Class template declaration or definition.
     TagOrTempResult = Actions.ActOnClassTemplate(CurScope, TagType, TK, 
                                                  StartLoc, SS, Name, NameLoc, 
                                                  Attr,
@@ -562,9 +563,28 @@
                                                       &(*TemplateParams)[0],
                                                       TemplateParams->size()),
                                                  AS);
-  else
-    TagOrTempResult = Actions.ActOnTag(CurScope, TagType, TK, StartLoc, SS, Name, 
-                                       NameLoc, Attr, AS);
+  } else if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation &&
+             TK == Action::TK_Declaration) {
+    // Explicit instantiation of a member of a class template
+    // specialization, e.g.,
+    //
+    //   template struct Outer<int>::Inner;
+    //
+    TagOrTempResult
+      = Actions.ActOnExplicitInstantiation(CurScope, 
+                                           TemplateInfo.TemplateLoc, 
+                                           TagType, StartLoc, SS, Name, 
+                                           NameLoc, Attr);
+  } else {
+    if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation &&
+        TK == Action::TK_Definition) {
+      // FIXME: Diagnose this particular error.
+    }
+
+    // Declaration or definition of a class type
+    TagOrTempResult = Actions.ActOnTag(CurScope, TagType, TK, StartLoc, SS, 
+                                       Name, NameLoc, Attr, AS);
+  }
 
   // Parse the optional base clause (C++ only).
   if (getLang().CPlusPlus && Tok.is(tok::colon))
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 2f1b9c8..4becfc8 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -149,7 +149,7 @@
       if (TemplateId->Kind == TNK_Type_template || 
           TemplateId->Kind == TNK_Dependent_template_name) {
         AnnotateTemplateIdTokenAsType(&SS);
-        SS.clear();
+        SS.setScopeRep(0);
 
         assert(Tok.is(tok::annot_typename) && 
                "AnnotateTemplateIdTokenAsType isn't working");
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 08f9b02..bd01ec9 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -1919,6 +1919,15 @@
                              SourceLocation RAngleLoc,
                              AttributeList *Attr);
 
+  virtual DeclResult
+  ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
+                             unsigned TagSpec, 
+                             SourceLocation KWLoc,
+                             const CXXScopeSpec &SS,
+                             IdentifierInfo *Name,
+                             SourceLocation NameLoc,
+                             AttributeList *Attr);
+
   bool CheckTemplateArgumentList(TemplateDecl *Template,
                                  SourceLocation TemplateLoc,
                                  SourceLocation LAngleLoc,
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index bbc1bc5..11ac0bd 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -273,8 +273,9 @@
                                                     SourceLocation CCLoc) {
   NestedNameSpecifier *Prefix 
     = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+  QualType T = QualType::getFromOpaquePtr(Ty);
   return NestedNameSpecifier::Create(Context, Prefix, /*FIXME:*/false,
-                                QualType::getFromOpaquePtr(Ty).getTypePtr());
+                                     T.getTypePtr());
 }
 
 /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 5914292..e27517e 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -3254,12 +3254,15 @@
       goto CreateNewDecl;
     }
 
-    // FIXME: RequireCompleteDeclContext(SS)?
+    if (RequireCompleteDeclContext(SS))
+      return DeclPtrTy::make((Decl *)0);
+
     DC = computeDeclContext(SS);
     SearchDC = DC;
     // Look-up name inside 'foo::'.
-    PrevDecl = dyn_cast_or_null<TagDecl>(
-                 LookupQualifiedName(DC, Name, LookupTagName, true).getAsDecl());
+    PrevDecl 
+      = dyn_cast_or_null<TagDecl>(
+               LookupQualifiedName(DC, Name, LookupTagName, true).getAsDecl());
 
     // A tag 'foo::bar' must already exist.
     if (PrevDecl == 0) {
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 5f2b705..57aae29 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -994,10 +994,7 @@
     Diag(Loc, diag::err_bad_memptr_rhs)
       << OpSpelling << RType << rex->getSourceRange();
     return QualType();
-  } else if (RequireCompleteType(Loc, QualType(MemPtr->getClass(), 0),
-                                 diag::err_memptr_rhs_incomplete,
-                                 rex->getSourceRange()))
-    return QualType();
+  } 
 
   QualType Class(MemPtr->getClass(), 0);
 
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 22f2bef..7190df1 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -2155,6 +2155,7 @@
   return DeclPtrTy::make(Specialization);
 }
 
+// Explicit instantiation of a class template specialization
 Sema::DeclResult
 Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
                                  unsigned TagSpec, 
@@ -2244,7 +2245,7 @@
     }
 
     if (PrevDecl->getSpecializationKind() == TSK_ExplicitSpecialization) {
-      // C++0x [temp.explicit]p4:
+      // C++ DR 259, C++0x [temp.explicit]p4:
       //   For a given set of template parameters, if an explicit
       //   instantiation of a template appears after a declaration of
       //   an explicit specialization for that template, the explicit
@@ -2342,6 +2343,84 @@
   return DeclPtrTy::make(Specialization);
 }
 
+// Explicit instantiation of a member class of a class template.
+Sema::DeclResult
+Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
+                                 unsigned TagSpec, 
+                                 SourceLocation KWLoc,
+                                 const CXXScopeSpec &SS,
+                                 IdentifierInfo *Name,
+                                 SourceLocation NameLoc,
+                                 AttributeList *Attr) {
+
+  DeclPtrTy TagD = ActOnTag(S, TagSpec, Action::TK_Reference,
+                            KWLoc, SS, Name, NameLoc, Attr, AS_none);
+  if (!TagD)
+    return true;
+
+  TagDecl *Tag = cast<TagDecl>(TagD.getAs<Decl>());
+  if (Tag->isEnum()) {
+    Diag(TemplateLoc, diag::err_explicit_instantiation_enum)
+      << Context.getTypeDeclType(Tag);
+    return true;
+  }
+
+  CXXRecordDecl *Record = cast<CXXRecordDecl>(Tag);
+  CXXRecordDecl *Pattern = Record->getInstantiatedFromMemberClass();
+  if (!Pattern) {
+    Diag(TemplateLoc, diag::err_explicit_instantiation_nontemplate_type)
+      << Context.getTypeDeclType(Record);
+    Diag(Record->getLocation(), diag::note_nontemplate_decl_here);
+    return true;
+  }
+
+  // C++0x [temp.explicit]p2:
+  //   [...] An explicit instantiation shall appear in an enclosing
+  //   namespace of its template. [...]
+  //
+  // This is C++ DR 275.
+  if (getLangOptions().CPlusPlus0x) {
+    // FIXME: In C++98, we would like to turn these errors into
+    // warnings, dependent on a -Wc++0x flag.
+    DeclContext *PatternContext 
+      = Pattern->getDeclContext()->getEnclosingNamespaceContext();
+    if (!CurContext->Encloses(PatternContext)) {
+      Diag(TemplateLoc, diag::err_explicit_instantiation_out_of_scope)
+        << Record << cast<NamedDecl>(PatternContext) << SS.getRange();
+      Diag(Pattern->getLocation(), diag::note_previous_declaration);
+    }
+  }
+
+  // Find the enclosing template, because we need its template
+  // arguments to instantiate this class.
+  DeclContext *EnclosingTemplateCtx = Record->getDeclContext();
+  while (!isa<ClassTemplateSpecializationDecl>(EnclosingTemplateCtx))
+    EnclosingTemplateCtx = EnclosingTemplateCtx->getParent();
+  ClassTemplateSpecializationDecl *EnclosingTemplate 
+    = cast<ClassTemplateSpecializationDecl>(EnclosingTemplateCtx);
+  
+  if (!Record->getDefinition(Context)) {
+    // If the class has a definition, instantiate it (and all of its
+    // members, recursively).
+    Pattern = cast_or_null<CXXRecordDecl>(Pattern->getDefinition(Context));
+    if (Pattern && InstantiateClass(TemplateLoc, Record, Pattern, 
+                                    EnclosingTemplate->getTemplateArgs(),
+                                    /*ExplicitInstantiation=*/true))
+      return true;
+  } else {
+    // Instantiate all of the members of class.
+    InstantiatingTemplate Inst(*this, TemplateLoc, Record);
+    InstantiateClassMembers(TemplateLoc, Record, 
+                            EnclosingTemplate->getTemplateArgs());
+  }
+
+  // FIXME: We don't have any representation for explicit
+  // instantiations of member classes. Such a representation is not
+  // needed for compilation, but it should be available for clients
+  // that want to see all of the declarations in the source code.
+  return TagD;
+}
+
 Sema::TypeResult
 Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
                         const IdentifierInfo &II, SourceLocation IdLoc) {
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 9c2c423..5c6ed75 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -863,7 +863,7 @@
                                  ActOnCXXNestedNameSpecifier(0, SS,
                                                              Range.getEnd(),
                                                              Range.getEnd(),
-                                                   *NNS->getAsIdentifier()));
+                                                    *NNS->getAsIdentifier()));
     break;
   }