diff options
author | Douglas Gregor <dgregor@apple.com> | 2010-05-17 17:57:54 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2010-05-17 17:57:54 +0000 |
commit | cfe833be882f600206f1587f157b025b368497d7 (patch) | |
tree | c4be0470a9c4f715e4238f850d5f6fcbfec26e95 | |
parent | 6cfacfe54c75baa4d67f1fbdf4f80644b662818e (diff) |
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
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 30 | ||||
-rw-r--r-- | 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<int> x1a; // expected-note 6{{in instantiation of}} +X1<int> x1a; // expected-note 7{{in instantiation of}} void f3(int) { } // expected-note{{previous definition}} void f5(int) { } // expected-note{{previous definition}} -X1<float> x1b; +X1<float> x1b; X1<double> *X0d() { return 0;} + +template<typename T> +struct X2 { + friend void g0(T) { } // expected-error{{redefinition of 'g0'}} +}; + +template<typename T> +struct X3 { + friend void g0(T) { } // expected-note{{previous definition is here}} +}; + +X2<float> x2; // expected-note{{in instantiation of}} +X3<float> x3; |