sepavloff updated this revision to Diff 51817.
sepavloff added a comment.

Changed implementation

This implementation uses another approach. Previous version of the patch put 
friend functions
into redeclaration chains but modified search algorithm so that it skipped such 
functions. In
this version such functions are not included into redeclaration chains at all.


http://reviews.llvm.org/D16989

Files:
  include/clang/Sema/Sema.h
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaDeclCXX.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp
  test/SemaCXX/PR25848.cpp
  test/SemaCXX/friend2.cpp

Index: test/SemaCXX/friend2.cpp
===================================================================
--- /dev/null
+++ test/SemaCXX/friend2.cpp
@@ -0,0 +1,145 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+
+// If a friend function is defined in several non-template classes,
+// it is an error.
+
+void func1(int);
+struct C1a {
+  friend void func1(int) {}  // expected-note{{previous definition is here}}
+};
+struct C1b {
+  friend void func1(int) {}  // expected-error{{redefinition of 'func1'}}
+};
+
+
+// If a friend function is defined in both non-template and template
+// classes it is an error only if the template is instantiated.
+
+void func2(int);
+struct C2a {
+  friend void func2(int) {}
+};
+template<typename T> struct C2b {
+  friend void func2(int) {}
+};
+
+void func3(int);
+struct C3a {
+  friend void func3(int) {}  // expected-note{{previous definition is here}}
+};
+template<typename T> struct C3b {
+  friend void func3(int) {}  // expected-error{{redefinition of 'func3'}}
+};
+C3b<long> c3;  // expected-note{{in instantiation of template class 'C3b<long>' requested here}}
+
+
+// If a friend function is defined in several template classes it is an error
+// only if several templates are instantiated.
+
+void func4(int);
+template<typename T> struct C4a {
+  friend void func4(int) {}
+};
+template<typename T> struct C4b {
+  friend void func4(int) {}
+};
+
+
+void func5(int);
+template<typename T> struct C5a {
+  friend void func5(int) {}
+};
+template<typename T> struct C5b {
+  friend void func5(int) {}
+};
+C5a<long> c5a;
+
+void func6(int);
+template<typename T> struct C6a {
+  friend void func6(int) {}  // expected-note{{previous definition is here}}
+};
+template<typename T> struct C6b {
+  friend void func6(int) {}  // expected-error{{redefinition of 'func6'}}
+};
+C6a<long> c6a;
+C6b<int*> c6b;  // expected-note{{in instantiation of template class 'C6b<int *>' requested here}}
+
+void func7(int);
+template<typename T> struct C7 {
+  friend void func7(int) {}  // expected-error{{redefinition of 'func7'}}
+                             // expected-note@-1{{previous definition is here}}
+};
+C7<long> c7a;
+C7<int*> c7b;  // expected-note{{in instantiation of template class 'C7<int *>' requested here}}
+
+
+// Even if clases are not instantiated and hence friend functions defined in them are not
+// available, their declarations must be checked.
+
+void func8(int);  // expected-note{{previous declaration is here}}
+template<typename T> struct C8a {
+  friend long func8(int);  // expected-error{{functions that differ only in their return type cannot be overloaded}}
+};
+
+void func9(int);  // expected-note{{previous declaration is here}}
+template<typename T> struct C9a {
+  friend int func9(int);  // expected-error{{functions that differ only in their return type cannot be overloaded}}
+};
+
+void func10(int);  // expected-note{{previous declaration is here}}
+template<typename T> struct C10a {
+  friend int func10(int);  // expected-error{{functions that differ only in their return type cannot be overloaded}}
+};
+
+
+namespace pr22307 {
+
+struct t {
+  friend int leak(t);
+};
+
+template<typename v>
+struct m {
+  friend int leak(t) { return sizeof(v); }  // expected-error{{redefinition of 'leak'}} expected-note{{previous definition is here}}
+};
+
+template struct m<char>;
+template struct m<short>;  // expected-note{{in instantiation of template class 'pr22307::m<short>' requested here}}
+
+int main() {
+  leak(t());
+}
+
+}
+
+namespace pr17923 {
+
+void f(unsigned long long);
+
+template<typename T> struct X {
+  friend void f(unsigned long long) {
+     T t;
+  }
+};
+
+int main() { f(1234); }
+
+}
+
+namespace pr17923a {
+
+int get();
+
+template< int value >
+class set {
+  friend int get()
+    { return value; } // return 0; is OK
+};
+
+template class set< 5 >;
+
+int main() {
+  get();
+}
+
+}
Index: test/SemaCXX/PR25848.cpp
===================================================================
--- /dev/null
+++ test/SemaCXX/PR25848.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+struct A;
+typedef int A::* P;
+
+inline P g();  // expected-warning{{inline function 'g' is not defined}}
+
+template<P M>
+struct R {
+  friend P g() {
+    return M;
+  }
+};
+
+void m() {
+  g();  // expected-note{{used here}}
+}
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1599,7 +1599,7 @@
   }
 
   SemaRef.CheckFunctionDeclaration(/*Scope*/ nullptr, Function, Previous,
-                                   isExplicitSpecialization);
+                   isExplicitSpecialization, D->isThisDeclarationADefinition());
 
   NamedDecl *PrincipalDecl = (TemplateParams
                               ? cast<NamedDecl>(FunctionTemplate)
@@ -1896,7 +1896,8 @@
   }
 
   if (!IsClassScopeSpecialization)
-    SemaRef.CheckFunctionDeclaration(nullptr, Method, Previous, false);
+    SemaRef.CheckFunctionDeclaration(nullptr, Method, Previous, false,
+                                     D->isThisDeclarationADefinition());
 
   if (D->isPure())
     SemaRef.CheckPureMethod(Method, SourceRange());
Index: lib/Sema/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -12660,6 +12660,18 @@
       Diag(NameInfo.getBeginLoc(), diag::err_friend_def_in_local_class);
     }
 
+  // If a friend non-dependent function is declared in a dependent context, do
+  // not put it into redeclaration chain of corresponding file level
+  // declarations. Such function will be available when the template will be
+  // instantiated.
+  } else if (CurContext->isDependentContext() &&
+             (D.getName().getKind() != UnqualifiedId::IK_TemplateId) &&
+             (SS.isInvalid() || !SS.isSet())) {
+    DC = CurContext;
+    while (!DC->isFileContext())
+      DC = DC->getParent();
+    LookupName(Previous, S);
+
   //   - There's no scope specifier, in which case we just go to the
   //     appropriate scope and look for a function or function template
   //     there as appropriate.
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -8034,7 +8034,7 @@
 
     if (!NewFD->isInvalidDecl())
       D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous,
-                                                  isExplicitSpecialization));
+                           isExplicitSpecialization, D.isFunctionDefinition()));
     else if (!Previous.empty())
       // Recover gracefully from an invalid redeclaration.
       D.setRedeclaration(true);
@@ -8175,7 +8175,7 @@
 
       if (!NewFD->isInvalidDecl())
         D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous,
-                                                    isExplicitSpecialization));
+                           isExplicitSpecialization, D.isFunctionDefinition()));
       else if (!Previous.empty())
         // Recover gracefully from an invalid redeclaration.
         D.setRedeclaration(true);
@@ -8450,7 +8450,8 @@
 /// \returns true if the function declaration is a redeclaration.
 bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
                                     LookupResult &Previous,
-                                    bool IsExplicitSpecialization) {
+                                    bool IsExplicitSpecialization,
+                                    bool IsDefinition) {
   assert(!NewFD->getReturnType()->isVariablyModifiedType() &&
          "Variably modified return types are not handled here");
 
@@ -8607,8 +8608,16 @@
       }
       
     } else {
-      // This needs to happen first so that 'inline' propagates.
-      NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl));
+      if (NewFD->isOutOfLine() &&
+          NewFD->getLexicalDeclContext()->isDependentContext() &&
+          IsDefinition)
+        // Do not put friend function definitions found in template classes to
+        // redeclaration chains. There may be several such definitions in
+        // different classes, they would cause redefinition errors otherwise.
+        Redeclaration = false;
+      else
+        // This needs to happen first so that 'inline' propagates.
+        NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl));
 
       if (isa<CXXMethodDecl>(NewFD))
         NewFD->setAccess(OldDecl->getAccess());
@@ -10939,6 +10948,13 @@
 Sema::CheckForFunctionRedefinition(FunctionDecl *FD,
                                    const FunctionDecl *EffectiveDefinition,
                                    SkipBodyInfo *SkipBody) {
+  // Don't complain if the given declaration corresponds to the friend function
+  // declared in a template class. Such declaration defines the function only if
+  // the template is instantiated, in the latter case the definition must be
+  // found in corresponding class instantiation.
+  if (FD->isOutOfLine() && FD->getLexicalDeclContext()->isDependentContext())
+    return;
+
   // Don't complain if we're in GNU89 mode and the previous definition
   // was an extern inline function.
   const FunctionDecl *Definition = EffectiveDefinition;
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -1691,7 +1691,8 @@
   // Returns true if the function declaration is a redeclaration
   bool CheckFunctionDeclaration(Scope *S,
                                 FunctionDecl *NewFD, LookupResult &Previous,
-                                bool IsExplicitSpecialization);
+                                bool IsExplicitSpecialization,
+                                bool IsDefinition);
   void CheckMain(FunctionDecl *FD, const DeclSpec &D);
   void CheckMSVCRTEntryPoint(FunctionDecl *FD);
   Decl *ActOnParamDeclarator(Scope *S, Declarator &D);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to