Improve handling of friend types in several ways:
  - When instantiating a friend type template, perform semantic
  analysis on the resulting type.
  - Downgrade the errors concerning friend type declarations that do
  not refer to classes to ExtWarns in C++98/03. C++0x allows
  practically any type to be befriended, and ignores the friend
  declaration if the type is not a class.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@100635 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 3375ccc..69f183c 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -476,47 +476,44 @@
 }
 
 Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
-  FriendDecl::FriendUnion FU;
-
   // Handle friend type expressions by simply substituting template
-  // parameters into the pattern type.
+  // parameters into the pattern type and checking the result.
   if (TypeSourceInfo *Ty = D->getFriendType()) {
     TypeSourceInfo *InstTy = 
       SemaRef.SubstType(Ty, TemplateArgs,
                         D->getLocation(), DeclarationName());
-    if (!InstTy) return 0;
-
-    // This assertion is valid because the source type was necessarily
-    // an elaborated-type-specifier with a record tag.
-    assert(getLangOptions().CPlusPlus0x || InstTy->getType()->isRecordType());
-
-    FU = InstTy;
-
-  // Handle everything else by appropriate substitution.
-  } else {
-    NamedDecl *ND = D->getFriendDecl();
-    assert(ND && "friend decl must be a decl or a type!");
-
-    // FIXME: We have a problem here, because the nested call to Visit(ND)
-    // will inject the thing that the friend references into the current
-    // owner, which is wrong.
-    Decl *NewND;
-
-    // Hack to make this work almost well pending a rewrite.
-    if (D->wasSpecialization()) {
-      // Totally egregious hack to work around PR5866
+    if (!InstTy) 
       return 0;
-    } else {
-      NewND = Visit(ND);
-    }
-    if (!NewND) return 0;
 
-    FU = cast<NamedDecl>(NewND);
+    FriendDecl *FD = SemaRef.CheckFriendTypeDecl(D->getFriendLoc(), InstTy);
+    if (!FD)
+      return 0;
+    
+    FD->setAccess(AS_public);
+    Owner->addDecl(FD);
+    return FD;
+  } 
+  
+  NamedDecl *ND = D->getFriendDecl();
+  assert(ND && "friend decl must be a decl or a type!");
+
+  // FIXME: We have a problem here, because the nested call to Visit(ND)
+  // will inject the thing that the friend references into the current
+  // owner, which is wrong.
+  Decl *NewND;
+
+  // Hack to make this work almost well pending a rewrite.
+  if (D->wasSpecialization()) {
+    // Totally egregious hack to work around PR5866
+    return 0;
+  } else {
+    NewND = Visit(ND);
   }
+  if (!NewND) return 0;
 
   FriendDecl *FD =
-    FriendDecl::Create(SemaRef.Context, Owner, D->getLocation(), FU,
-                       D->getFriendLoc());
+    FriendDecl::Create(SemaRef.Context, Owner, D->getLocation(), 
+                       cast<NamedDecl>(NewND), D->getFriendLoc());
   FD->setAccess(AS_public);
   Owner->addDecl(FD);
   return FD;