]> granicus.if.org Git - clang/commitdiff
Split Sema::ActOnFriendTypeDecl into Sema::CheckFriendTypeDecl (for
authorDouglas Gregor <dgregor@apple.com>
Wed, 7 Apr 2010 16:53:43 +0000 (16:53 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 7 Apr 2010 16:53:43 +0000 (16:53 +0000)
semantic analysis) and Sema::ActOnFriendTypeDecl (the action
callback). This is a prerequisite for improving template instantiation
of friend type declarations.

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

lib/Sema/Sema.h
lib/Sema/SemaDeclCXX.cpp

index 5394f06985d1de484711a5e6e04e31bc7f4f45a7..c93acf69461e8723dbf98ab0b18764d7a1a9c97b 100644 (file)
@@ -2530,6 +2530,8 @@ public:
                                                  ExprArg AssertExpr,
                                                  ExprArg AssertMessageExpr);
 
+  FriendDecl *CheckFriendTypeDecl(SourceLocation FriendLoc, 
+                                  TypeSourceInfo *TSInfo);
   DeclPtrTy ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
                                 MultiTemplateParamsArg TemplateParams);
   DeclPtrTy ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition,
index 39e3739878f9b744aa84c9d431c874a826348079..75dbb46d42378749a76d6b080b9ca6b5636dec4d 100644 (file)
@@ -5318,6 +5318,53 @@ Sema::DeclPtrTy Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc,
   return DeclPtrTy::make(Decl);
 }
 
+/// \brief Perform semantic analysis of the given friend type declaration.
+///
+/// \returns A friend declaration that.
+FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation FriendLoc, 
+                                      TypeSourceInfo *TSInfo) {
+  assert(TSInfo && "NULL TypeSourceInfo for friend type declaration");
+  
+  QualType T = TSInfo->getType();
+  SourceRange TypeRange = TSInfo->getTypeLoc().getSourceRange();
+  
+  // C++03 [class.friend]p2:
+  //   An elaborated-type-specifier shall be used in a friend declaration
+  //   for a class.*
+  //
+  //   * The class-key of the elaborated-type-specifier is required.
+  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>()) {
+      RecordDecl *RD = RT->getDecl();
+      
+      std::string InsertionText = std::string(" ") + RD->getKindName();
+      
+      Diag(FriendLoc, diag::err_unelaborated_friend_type)
+        << (unsigned) RD->getTagKind()
+        << T
+        << SourceRange(FriendLoc)
+        << FixItHint::CreateInsertion(TypeRange.getBegin(),
+                                      InsertionText);
+      return 0; 
+    } else {
+      Diag(FriendLoc, diag::err_unexpected_friend)
+        << SourceRange(FriendLoc, TypeRange.getEnd());
+      return 0;
+    }
+  }
+  
+  // Enum types cannot be friends.
+  if (T->getAs<EnumType>()) {
+    Diag(FriendLoc, diag::err_enum_friend)
+      << SourceRange(FriendLoc, TypeRange.getEnd());
+    return 0;
+  }  
+  
+  return FriendDecl::Create(Context, CurContext, FriendLoc, TSInfo, FriendLoc);
+}
+
 /// Handle a friend type declaration.  This works in tandem with
 /// ActOnTag.
 ///
@@ -5351,6 +5398,9 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
   if (TheDeclarator.isInvalidType())
     return DeclPtrTy();
 
+  if (!TSI)
+    TSI = Context.getTrivialTypeSourceInfo(T, DS.getSourceRange().getBegin());
+  
   // This is definitely an error in C++98.  It's probably meant to
   // be forbidden in C++0x, too, but the specification is just
   // poorly written.
@@ -5370,38 +5420,11 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
       << DS.getSourceRange();
     return DeclPtrTy();
   }
-
-  // C++ [class.friend]p2:
-  //   An elaborated-type-specifier shall be used in a friend declaration
-  //   for a class.*
-  //   * 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 && !T->isElaboratedTypeSpecifier()) {
-    // If we evaluated the type to a record type, suggest putting
-    // a tag in front.
-    if (const RecordType *RT = T->getAs<RecordType>()) {
-      RecordDecl *RD = RT->getDecl();
-
-      std::string InsertionText = std::string(" ") + RD->getKindName();
-
-      Diag(DS.getTypeSpecTypeLoc(), diag::err_unelaborated_friend_type)
-        << (unsigned) RD->getTagKind()
-        << T
-        << SourceRange(DS.getFriendSpecLoc())
-        << FixItHint::CreateInsertion(DS.getTypeSpecTypeLoc(), InsertionText);
-      return DeclPtrTy();
-    }else {
-      Diag(DS.getFriendSpecLoc(), diag::err_unexpected_friend)
-          << DS.getSourceRange();
-      return DeclPtrTy();
-    }
-  }
-
-  // Enum types cannot be friends.
-  if (T->getAs<EnumType>()) {
+  
+  // Enum templates cannot be friends.
+  if (TempParams.size() && T->getAs<EnumType>()) {
     Diag(DS.getTypeSpecTypeLoc(), diag::err_enum_friend)
-      << SourceRange(DS.getFriendSpecLoc());
+    << SourceRange(DS.getFriendSpecLoc());
     return DeclPtrTy();
   }
 
@@ -5417,15 +5440,18 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
   // friend a member of an arbitrary specialization of your template).
 
   Decl *D;
-  if (TempParams.size())
+  if (unsigned NumTempParamLists = TempParams.size())
     D = FriendTemplateDecl::Create(Context, CurContext, Loc,
-                                   TempParams.size(),
+                                   NumTempParamLists,
                                  (TemplateParameterList**) TempParams.release(),
                                    TSI,
                                    DS.getFriendSpecLoc());
   else
-    D = FriendDecl::Create(Context, CurContext, Loc, TSI,
-                           DS.getFriendSpecLoc());
+    D = CheckFriendTypeDecl(DS.getFriendSpecLoc(), TSI);
+  
+  if (!D)
+    return DeclPtrTy();
+  
   D->setAccess(AS_public);
   CurContext->addDecl(D);