From cfe833be882f600206f1587f157b025b368497d7 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Mon, 17 May 2010 17:57:54 +0000 Subject: [PATCH] Diagnose a redefinition error when there are two instantiations of friend functions defined inside a class template. Fixes PR6952, the last Boost.Units failure. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@103952 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaTemplateInstantiateDecl.cpp | 30 ++++++++++++++++++++- test/CXX/temp/temp.decls/temp.friend/p4.cpp | 22 +++++++++++---- 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 31284071ff..1280c0cb88 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2000,7 +2000,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, Diag(Function->getLocation(), diag::err_redefinition) << Function->getDeclName(); Diag(Definition->getLocation(), diag::note_previous_definition); - } + Function->setInvalidDecl(); + } // We have an explicit instantiation (which already occurred) and an // implicit instantiation. Return without complaint. @@ -2027,11 +2028,38 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, if (PatternDecl) Diag(PatternDecl->getLocation(), diag::note_explicit_instantiation_here); + Function->setInvalidDecl(); } return; } + // If this is an instantiation of friend function defined within a class + // template or class template specialization or member class thereof, + // determine whether there were multiple instantiations of its lexical class. + if (PatternDecl->getFriendObjectKind() != Decl::FOK_None) { + for (FunctionDecl::redecl_iterator R = Function->redecls_begin(), + REnd = Function->redecls_end(); + R != REnd; ++R) { + if (*R != Function && + ((*R)->getFriendObjectKind() != Decl::FOK_None)) { + if (const FunctionDecl *RPattern + = (*R)->getTemplateInstantiationPattern()) + if (RPattern->getBody(RPattern)) { + InstantiatingTemplate Inst(*this, PointOfInstantiation, Function); + if (Inst) + return; + + Diag(Function->getLocation(), diag::err_redefinition) + << Function->getDeclName(); + Diag((*R)->getLocation(), diag::note_previous_definition); + Function->setInvalidDecl(); + return; + } + } + } + } + // C++0x [temp.explicit]p9: // Except for inline functions, other explicit instantiation declarations // have the effect of suppressing the implicit instantiation of the entity diff --git a/test/CXX/temp/temp.decls/temp.friend/p4.cpp b/test/CXX/temp/temp.decls/temp.friend/p4.cpp index a1d7c6933f..e408720833 100644 --- a/test/CXX/temp/temp.decls/temp.friend/p4.cpp +++ b/test/CXX/temp/temp.decls/temp.friend/p4.cpp @@ -21,20 +21,32 @@ struct X1 { friend void f3(T) { } // expected-error{{redefinition of}} friend void f4(T) { } // expected-error{{redefinition of}} friend void f5(T) { } // expected-error{{redefinition of}} - - // FIXME: should have a redefinition error for f6(int) - friend void f6(int) { } + friend void f6(int) { } // expected-error{{redefinition of}} \ + // expected-note{{previous definition}} }; void f2(int) { } // expected-note{{previous definition}} void f4(int) { } // expected-note{{previous definition}} -X1 x1a; // expected-note 6{{in instantiation of}} +X1 x1a; // expected-note 7{{in instantiation of}} void f3(int) { } // expected-note{{previous definition}} void f5(int) { } // expected-note{{previous definition}} -X1 x1b; +X1 x1b; X1 *X0d() { return 0;} + +template +struct X2 { + friend void g0(T) { } // expected-error{{redefinition of 'g0'}} +}; + +template +struct X3 { + friend void g0(T) { } // expected-note{{previous definition is here}} +}; + +X2 x2; // expected-note{{in instantiation of}} +X3 x3; -- 2.40.0