]> granicus.if.org Git - clang/commitdiff
White-listing templated-scope friend decls is a good idea, but doing it
authorJohn McCall <rjmccall@apple.com>
Sat, 16 Oct 2010 06:59:13 +0000 (06:59 +0000)
committerJohn McCall <rjmccall@apple.com>
Sat, 16 Oct 2010 06:59:13 +0000 (06:59 +0000)
by marking the decl invalid isn't.  Make some steps towards supporting these
and then hastily shut them down at the last second by marking them as
unsupported.

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

include/clang/AST/DeclFriend.h
lib/Sema/SemaAccess.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaTemplate.cpp
lib/Serialization/ASTReaderDecl.cpp
lib/Serialization/ASTWriterDecl.cpp
test/CodeGenCXX/template-instantiation.cpp

index 4b5e6fd48bb3ccae0c1d162314d8973218883a15..10befe0831673e9d43151de4984ee858099d89e6 100644 (file)
@@ -48,6 +48,11 @@ private:
   // Location of the 'friend' specifier.
   SourceLocation FriendLoc;
 
+  /// True if this 'friend' declaration is unsupported.  Eventually we
+  /// will support every possible friend declaration, but for now we
+  /// silently ignore some and set this flag to authorize all access.
+  bool UnsupportedFriend;
+
   friend class CXXRecordDecl::friend_iterator;
   friend class CXXRecordDecl;
 
@@ -56,7 +61,8 @@ private:
     : Decl(Decl::Friend, DC, L),
       Friend(Friend),
       NextFriend(0),
-      FriendLoc(FriendL) {
+      FriendLoc(FriendL),
+      UnsupportedFriend(false) {
   }
 
   explicit FriendDecl(EmptyShell Empty)
@@ -87,6 +93,14 @@ public:
     return FriendLoc;
   }
 
+  /// Determines if this friend kind is unsupported.
+  bool isUnsupportedFriend() const {
+    return UnsupportedFriend;
+  }
+  void setUnsupportedFriend(bool Unsupported) {
+    UnsupportedFriend = Unsupported;
+  }
+
   // Implement isa/cast/dyncast/etc.
   static bool classof(const Decl *D) { return classofKind(D->getKind()); }
   static bool classof(const FriendDecl *D) { return true; }
index ea6481bd8ab80328dcc4a9bc3a8d85490bd69407..c3a1e7521050bb1d38cbf98c8aa7eac831705fac 100644 (file)
@@ -516,8 +516,9 @@ static AccessResult MatchesFriend(Sema &S,
 static AccessResult MatchesFriend(Sema &S,
                                   const EffectiveContext &EC,
                                   FriendDecl *FriendD) {
-  // Whitelist accesses if there's an invalid friend declaration.
-  if (FriendD->isInvalidDecl())
+  // Whitelist accesses if there's an invalid or unsupported friend
+  // declaration.
+  if (FriendD->isInvalidDecl() || FriendD->isUnsupportedFriend())
     return AR_accessible;
 
   if (TypeSourceInfo *T = FriendD->getFriendType())
index e7714521c844be9cab7aa68bc0e12a82b8861b93..d11819461ece189b4bbbf407a34eb3bf0bf7f154 100644 (file)
@@ -3410,11 +3410,11 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
         = MatchTemplateParametersToScopeSpecifier(
                                   D.getDeclSpec().getSourceRange().getBegin(),
                                   D.getCXXScopeSpec(),
-                           (TemplateParameterList**)TemplateParamLists.get(),
-                                                  TemplateParamLists.size(),
-                                                  isFriend,
-                                                  isExplicitSpecialization,
-                                                  Invalid)) {
+                                  TemplateParamLists.get(),
+                                  TemplateParamLists.size(),
+                                  isFriend,
+                                  isExplicitSpecialization,
+                                  Invalid)) {
     // All but one template parameter lists have been matching.
     --NumMatchedTemplateParamLists;
 
@@ -3462,7 +3462,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
   if (NumMatchedTemplateParamLists > 0 && D.getCXXScopeSpec().isSet()) {
     NewFD->setTemplateParameterListsInfo(Context,
                                          NumMatchedTemplateParamLists,
-                        (TemplateParameterList**)TemplateParamLists.release());
+                                         TemplateParamLists.release());
   }
 
   if (Invalid) {
@@ -3732,14 +3732,20 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
 
     // Qualified decls generally require a previous declaration.
     if (D.getCXXScopeSpec().isSet()) {
-      // ...with the major exception of dependent friend declarations.
-      // In theory, this condition could be whether the qualifier
-      // is dependent;  in practice, the way we nest template parameters
-      // prevents this sort of matching from working, so we have to base it
-      // on the general dependence of the context.
-      if (isFriend && CurContext->isDependentContext()) {
+      // ...with the major exception of templated-scope or
+      // dependent-scope friend declarations.
+
+      // TODO: we currently also suppress this check in dependent
+      // contexts because (1) the parameter depth will be off when
+      // matching friend templates and (2) we might actually be
+      // selecting a friend based on a dependent factor.  But there
+      // are situations where these conditions don't apply and we
+      // can actually do this check immediately.
+      if (isFriend &&
+          (NumMatchedTemplateParamLists ||
+           D.getCXXScopeSpec().getScopeRep()->isDependent() ||
+           CurContext->isDependentContext())) {
         // ignore these
-
       } else {
         // The user tried to provide an out-of-line definition for a
         // function that is a member of a class or namespace, but there
index be1ee358e2a98ea3964d6d4da8279cd03a63c496..583f7c59b41ac1597a0d7a3a5c0ca84b0f75cb81 100644 (file)
@@ -6532,6 +6532,17 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition,
 
   if (ND->isInvalidDecl())
     FrD->setInvalidDecl();
+  else {
+    FunctionDecl *FD;
+    if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(ND))
+      FD = FTD->getTemplatedDecl();
+    else
+      FD = cast<FunctionDecl>(ND);
+
+    // Mark templated-scope function declarations as unsupported.
+    if (FD->getNumTemplateParameterLists())
+      FrD->setUnsupportedFriend(true);
+  }
 
   return ND;
 }
index f85c3f00709e64172271f88c650f1f59a9f2d9fe..66ded48c2402b57d077d11260b14d257c61087de 100644 (file)
@@ -1375,13 +1375,8 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
   // If there were at least as many template-ids as there were template
   // parameter lists, then there are no template parameter lists remaining for
   // the declaration itself.
-  if (Idx >= NumParamLists) {
-    // Silently drop template member friend declarations.
-    // TODO: implement these
-    if (IsFriend && NumParamLists) Invalid = true;
-
+  if (Idx >= NumParamLists)
     return 0;
-  }
 
   // If there were too many template parameter lists, complain about that now.
   if (Idx != NumParamLists - 1) {
@@ -1410,11 +1405,6 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
     }
   }
 
-  // Silently drop template member template friend declarations.
-  // TODO: implement these
-  if (IsFriend && NumParamLists > 1)
-    Invalid = true;
-
   // Return the last template parameter list, which corresponds to the
   // entity being declared.
   return ParamLists[NumParamLists - 1];
index c89273567e551d45860aeef5a235adc6acc2cc23..05ade6371950837a52f5080fe25c5ac69b90d72d 100644 (file)
@@ -908,6 +908,7 @@ void ASTDeclReader::VisitFriendDecl(FriendDecl *D) {
   else
     D->Friend = cast<NamedDecl>(Reader.GetDecl(Record[Idx++]));
   D->NextFriend = cast_or_null<FriendDecl>(Reader.GetDecl(Record[Idx++]));
+  D->UnsupportedFriend = (Record[Idx++] != 0);
   D->FriendLoc = ReadSourceLocation(Record, Idx);
 }
 
index 0dcc822fbc9e5549598ea6822a3afa299b719703..bf7c259635f2a9f086b67e9e9ac17bc3dfb6485f 100644 (file)
@@ -835,6 +835,7 @@ void ASTDeclWriter::VisitFriendDecl(FriendDecl *D) {
   else
     Writer.AddDeclRef(D->Friend.get<NamedDecl*>(), Record);
   Writer.AddDeclRef(D->NextFriend, Record);
+  Record.push_back(D->UnsupportedFriend);
   Writer.AddSourceLocation(D->FriendLoc, Record);
   Code = serialization::DECL_FRIEND;
 }
index 47ff16b8a62428f8b454de6f63c25b87ab23a063..a8729035e286755edef60b77cd2b326be3e9e76f 100644 (file)
@@ -92,3 +92,20 @@ namespace test3 {
   // don't have key functions.
   template void S<int>::m();
 }
+
+namespace test4 {
+  template <class T> struct A { static void foo(); };
+
+  class B {
+    template <class T> friend void A<T>::foo();
+    B();
+  };
+
+  template <class T> void A<T>::foo() {
+    B b;
+  }
+
+  unsigned test() {
+    A<int>::foo();
+  }
+}