]> granicus.if.org Git - clang/commitdiff
Implement the restrictions in C++ [class.friend]p6, which disallow
authorDouglas Gregor <dgregor@apple.com>
Mon, 10 Oct 2011 01:11:59 +0000 (01:11 +0000)
committerDouglas Gregor <dgregor@apple.com>
Mon, 10 Oct 2011 01:11:59 +0000 (01:11 +0000)
defining a friend function with a qualified name or in a local
class. Fixes PR9853.

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

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaDeclCXX.cpp
test/CXX/class.access/class.friend/p6.cpp [new file with mode: 0644]

index 8356340a2244bab04cdd2b19a8fbe7e1e12dbb88..c4e0168ce7cc4c421fd80e2b8ee3c8c7cf337e0e 100644 (file)
@@ -637,7 +637,11 @@ def err_no_matching_local_friend_suggest : Error<
   "no matching function %0 found in local scope; did you mean %2">;
 def err_partial_specialization_friend : Error<
   "partial specialization cannot be declared as a friend">;
-
+def err_qualified_friend_def : Error<
+  "friend function definition cannot be qualified with '%0'">;
+def err_friend_def_in_local_class : Error<
+  "friend function cannot be defined in a local class">;
+  
 def err_abstract_type_in_decl : Error<
   "%select{return|parameter|variable|field}0 type %1 is an abstract class">;
 def err_allocation_of_abstract_type : Error<
index 031afa078dac57f0461409ca253e5666527c6658..b16cbb80c40ca52df9ab50404e4a506c2b994132 100644 (file)
@@ -10196,6 +10196,14 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition,
 
     DCScope = getScopeForDeclContext(S, DC);
 
+    // C++ [class.friend]p6:
+    //   A function can be defined in a friend declaration of a class if and 
+    //   only if the class is a non-local class (9.8), the function name is
+    //   unqualified, and the function has namespace scope.
+    if (isLocal && IsDefinition) {
+      Diag(NameInfo.getBeginLoc(), diag::err_friend_def_in_local_class);
+    }
+    
   //   - There's a non-dependent scope specifier, in which case we
   //     compute it and do a previous lookup there for a function
   //     or function template.
@@ -10229,6 +10237,20 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition,
     //   class that is not a member of the class . . .
     if (DC->Equals(CurContext))
       Diag(DS.getFriendSpecLoc(), diag::err_friend_is_member);
+    
+    if (IsDefinition) {
+      // C++ [class.friend]p6:
+      //   A function can be defined in a friend declaration of a class if and 
+      //   only if the class is a non-local class (9.8), the function name is
+      //   unqualified, and the function has namespace scope.
+      SemaDiagnosticBuilder DB
+        = Diag(SS.getRange().getBegin(), diag::err_qualified_friend_def);
+      
+      DB << SS.getScopeRep();
+      if (DC->isFileContext())
+        DB << FixItHint::CreateRemoval(SS.getRange());
+      SS.clear();
+    }
 
   //   - There's a scope specifier that does not match any template
   //     parameter lists, in which case we use some arbitrary context,
@@ -10236,10 +10258,19 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition,
   //   - There's a scope specifier that does match some template
   //     parameter lists, which we don't handle right now.
   } else {
+    if (IsDefinition) {
+      // C++ [class.friend]p6:
+      //   A function can be defined in a friend declaration of a class if and 
+      //   only if the class is a non-local class (9.8), the function name is
+      //   unqualified, and the function has namespace scope.
+      Diag(SS.getRange().getBegin(), diag::err_qualified_friend_def)
+        << SS.getScopeRep();
+    }
+    
     DC = CurContext;
     assert(isa<CXXRecordDecl>(DC) && "friend declaration not in class?");
   }
-
+  
   if (!DC->isRecord()) {
     // This implies that it has to be an operator or function.
     if (D.getName().getKind() == UnqualifiedId::IK_ConstructorName ||
@@ -10251,7 +10282,7 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition,
       return 0;
     }
   }
-
+    
   bool Redeclaration = false;
   bool AddToScope = true;
   NamedDecl *ND = ActOnFunctionDeclarator(DCScope, D, DC, T, TInfo, Previous,
diff --git a/test/CXX/class.access/class.friend/p6.cpp b/test/CXX/class.access/class.friend/p6.cpp
new file mode 100644 (file)
index 0000000..7f7d909
--- /dev/null
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+void f1();
+
+struct X {
+  void f2();
+};
+
+struct Y {
+  friend void ::f1() { } // expected-error{{friend function definition cannot be qualified with '::'}}
+  friend void X::f2() { } // expected-error{{friend function definition cannot be qualified with 'X::'}}
+};
+
+void local() {
+  void f();
+
+  struct Local {
+    friend void f() { } // expected-error{{friend function cannot be defined in a local class}}
+  };
+}