Support elaborated dependent types and diagnose tag mismatches.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@81504 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 5d62c0c..f08c481 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -1641,10 +1641,12 @@
   else
     TUK = Action::TUK_Reference;
   bool Owned = false;
+  bool IsDependent = false;
   DeclPtrTy TagDecl = Actions.ActOnTag(CurScope, DeclSpec::TST_enum, TUK,
                                        StartLoc, SS, Name, NameLoc, Attr, AS,
                                        Action::MultiTemplateParamsArg(Actions),
-                                       Owned);
+                                       Owned, IsDependent);
+  assert(!IsDependent && "didn't expect dependent enum");
 
   if (Tok.is(tok::l_brace))
     ParseEnumBody(StartLoc, TagDecl);
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index fc3e6ae..8fa8525 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -619,7 +619,8 @@
   }
 
   // Create the tag portion of the class or class template.
-  Action::DeclResult TagOrTempResult;
+  Action::DeclResult TagOrTempResult = true; // invalid
+  Action::TypeResult TypeResult = true; // invalid
   TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams;
 
   // FIXME: When TUK == TUK_Reference and we have a template-id, we need
@@ -651,7 +652,7 @@
                                              TemplateId->RAngleLoc,
                                              Attr);
     } else if (TUK == Action::TUK_Reference || TUK == Action::TUK_Friend) {
-      Action::TypeResult Type
+      TypeResult
         = Actions.ActOnTemplateIdType(TemplateTy::make(TemplateId->Template),
                                       TemplateId->TemplateNameLoc,
                                       TemplateId->LAngleLoc,
@@ -659,23 +660,8 @@
                                       TemplateId->getTemplateArgLocations(),
                                       TemplateId->RAngleLoc);
 
-      Type = Actions.ActOnTagTemplateIdType(Type, TUK, TagType, StartLoc);
-
-      TemplateId->Destroy();
-
-      if (Type.isInvalid()) {
-        DS.SetTypeSpecError();
-        return;
-      }
-
-      const char *PrevSpec = 0;
-      unsigned DiagID;
-      if (DS.SetTypeSpecType(DeclSpec::TST_typename, StartLoc, PrevSpec,
-                             DiagID, Type.get()))
-        Diag(StartLoc, DiagID) << PrevSpec;
-
-      return;
-
+      TypeResult = Actions.ActOnTagTemplateIdType(TypeResult, TUK,
+                                                  TagType, StartLoc);
     } else {
       // This is an explicit specialization or a class template
       // partial specialization.
@@ -746,13 +732,21 @@
       // FIXME: Diagnose this particular error.
     }
 
+    bool IsDependent = false;
+
     // Declaration or definition of a class type
     TagOrTempResult = Actions.ActOnTag(CurScope, TagType, TUK, StartLoc, SS,
                                        Name, NameLoc, Attr, AS,
                                   Action::MultiTemplateParamsArg(Actions,
                                     TemplateParams? &(*TemplateParams)[0] : 0,
                                     TemplateParams? TemplateParams->size() : 0),
-                                       Owned);
+                                       Owned, IsDependent);
+
+    // If ActOnTag said the type was dependent, try again with the
+    // less common call.
+    if (IsDependent)
+      TypeResult = Actions.ActOnDependentTag(CurScope, TagType, TUK,
+                                             SS, Name, StartLoc, NameLoc);      
   }
 
   // Parse the optional base clause (C++ only).
@@ -771,15 +765,23 @@
     Diag(Tok, diag::err_expected_lbrace);
   }
 
-  if (TagOrTempResult.isInvalid()) {
+  void *Result;
+  if (!TypeResult.isInvalid()) {
+    TagType = DeclSpec::TST_typename;
+    Result = TypeResult.get();
+    Owned = false;
+  } else if (!TagOrTempResult.isInvalid()) {
+    Result = TagOrTempResult.get().getAs<void>();
+  } else {
     DS.SetTypeSpecError();
     return;
   }
 
   const char *PrevSpec = 0;
   unsigned DiagID;
+
   if (DS.SetTypeSpecType(TagType, StartLoc, PrevSpec, DiagID,
-                         TagOrTempResult.get().getAs<void>(), Owned))
+                         Result, Owned))
     Diag(StartLoc, DiagID) << PrevSpec;
 }
 
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index dc41aba..b17e54e 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -609,7 +609,15 @@
                              IdentifierInfo *Name, SourceLocation NameLoc,
                              AttributeList *Attr, AccessSpecifier AS,
                              MultiTemplateParamsArg TemplateParameterLists,
-                             bool &OwnedDecl);
+                             bool &OwnedDecl, bool &IsDependent);
+
+  virtual TypeResult ActOnDependentTag(Scope *S,
+                                       unsigned TagSpec,
+                                       TagUseKind TUK,
+                                       const CXXScopeSpec &SS,
+                                       IdentifierInfo *Name,
+                                       SourceLocation TagLoc,
+                                       SourceLocation NameLoc);
 
   virtual void ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart,
                          IdentifierInfo *ClassName,
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 65516f2..53fab18 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -3988,7 +3988,7 @@
                                IdentifierInfo *Name, SourceLocation NameLoc,
                                AttributeList *Attr, AccessSpecifier AS,
                                MultiTemplateParamsArg TemplateParameterLists,
-                               bool &OwnedDecl) {
+                               bool &OwnedDecl, bool &IsDependent) {
   // If this is not a definition, it must have a name.
   assert((Name != 0 || TUK == TUK_Definition) &&
          "Nameless record must be a definition!");
@@ -4034,6 +4034,16 @@
       goto CreateNewDecl;
     }
 
+    // If this is a friend or a reference to a class in a dependent
+    // context, don't try to make a decl for it.
+    if (TUK == TUK_Friend || TUK == TUK_Reference) {
+      DC = computeDeclContext(SS, false);
+      if (!DC) {
+        IsDependent = true;
+        return DeclPtrTy();
+      }
+    }
+
     if (RequireCompleteDeclContext(SS))
       return DeclPtrTy::make((Decl *)0);
 
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index fceac85..63c29de 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -1159,9 +1159,10 @@
 
     if (!isAcceptableTagRedeclaration(D, TagKind, TagLoc, *Id)) {
       Diag(TagLoc, diag::err_use_with_wrong_tag)
-        << Id
+        << Type
         << CodeModificationHint::CreateReplacement(SourceRange(TagLoc),
                                                    D->getKindName());
+      Diag(D->getLocation(), diag::note_previous_use);
     }
   }
 
@@ -3058,9 +3059,13 @@
                                  AttributeList *Attr) {
 
   bool Owned = false;
+  bool IsDependent = false;
   DeclPtrTy TagD = ActOnTag(S, TagSpec, Action::TUK_Reference,
                             KWLoc, SS, Name, NameLoc, Attr, AS_none,
-                            MultiTemplateParamsArg(*this, 0, 0), Owned);
+                            MultiTemplateParamsArg(*this, 0, 0),
+                            Owned, IsDependent);
+  assert(!IsDependent && "explicit instantiation of dependent name not yet handled");
+
   if (!TagD)
     return true;
 
@@ -3124,6 +3129,28 @@
 }
 
 Sema::TypeResult
+Sema::ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
+                        const CXXScopeSpec &SS, IdentifierInfo *Name,
+                        SourceLocation TagLoc, SourceLocation NameLoc) {
+  // This has to hold, because SS is expected to be defined.
+  assert(Name && "Expected a name in a dependent tag");
+
+  NestedNameSpecifier *NNS
+    = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+  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();
+}
+
+Sema::TypeResult
 Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
                         const IdentifierInfo &II, SourceLocation IdLoc) {
   NestedNameSpecifier *NNS
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 651d4a5..e719bbd 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -391,6 +391,10 @@
                                   IdentifierInfo *Name,
                                   SourceLocation Loc, SourceRange TypeRange);
 
+    /// \brief Check for tag mismatches when instantiating an
+    /// elaborated type.
+    QualType RebuildElaboratedType(QualType T, ElaboratedType::TagKind Tag);
+
     Sema::OwningExprResult TransformPredefinedExpr(PredefinedExpr *E);
     Sema::OwningExprResult TransformDeclRefExpr(DeclRefExpr *E);
 
@@ -451,7 +455,33 @@
   return Var;
 }
 
-Sema::OwningExprResult
+QualType
+TemplateInstantiator::RebuildElaboratedType(QualType T,
+                                            ElaboratedType::TagKind Tag) {
+  if (const TagType *TT = T->getAs<TagType>()) {
+    TagDecl* TD = TT->getDecl();
+
+    // FIXME: this location is very wrong;  we really need typelocs.
+    SourceLocation TagLocation = TD->getTagKeywordLoc();
+
+    // FIXME: type might be anonymous.
+    IdentifierInfo *Id = TD->getIdentifier();
+
+    // TODO: should we even warn on struct/class mismatches for this?  Seems
+    // like it's likely to produce a lot of spurious errors.
+    if (!SemaRef.isAcceptableTagRedeclaration(TD, Tag, TagLocation, *Id)) {
+      SemaRef.Diag(TagLocation, diag::err_use_with_wrong_tag)
+        << Id
+        << CodeModificationHint::CreateReplacement(SourceRange(TagLocation),
+                                                   TD->getKindName());
+      SemaRef.Diag(TD->getLocation(), diag::note_previous_use);
+    }
+  }
+
+  return TreeTransform<TemplateInstantiator>::RebuildElaboratedType(T, Tag);
+}
+
+Sema::OwningExprResult 
 TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E) {
   if (!E->isTypeDependent())
     return SemaRef.Owned(E->Retain());