From b92ea59481c5df7ae2b3605d5c4a578778172890 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Tue, 18 May 2010 05:45:02 +0000 Subject: [PATCH] I hate this commit. Revert much of the implementation of C++98/03 [temp.friend]p5 in r103943 and its follow-ons r103948 and r103952. While our implementation was technically correct, other compilers don't seem to implement this paragraph (which forces the instantiation of friend functions defined in a class template when a class template specialization is instantiated), and doing so broke a bunch of Boost libraries. Since this behavior has changed in C++0x (which instantiates the friend function definitions when they are used), we're going to skip the nowhere-implemented C++98/03 semantics and go straight to the C++0x semantics. This commit is a band-aid to get Boost up and running again. It doesn't really fix PR6952 (which this commit un-fixes), but it does deal with the way Boost.Units abuses this particular paragraph. llvm-svn: 104014 --- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 103 ++++++------------ .../test/CXX/class.access/class.friend/p1.cpp | 4 +- .../CXX/temp/temp.decls/temp.friend/p4.cpp | 46 +------- 3 files changed, 37 insertions(+), 116 deletions(-) diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index f3d37787f81e..592b474dfb76 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1049,23 +1049,6 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, // TODO: should we remember this connection regardless of whether // the friend declaration provided a body? Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation); - if (!SemaRef.getLangOptions().CPlusPlus0x) { - // C++03 [temp.friend]p4: - // When a function is defined in a friend function declaration in a - // class template, the function is defined at each instantiation of the - // class template. The function is defined even if it is never used. - if (CXXRecordDecl *Record = dyn_cast(Owner)) { - if (ClassTemplateSpecializationDecl *Spec - = dyn_cast(Record)) - InstantiateAtPOI = Spec->getPointOfInstantiation(); - else if (MemberSpecializationInfo *MSInfo - = Record->getMemberSpecializationInfo()) - InstantiateAtPOI = MSInfo->getPointOfInstantiation(); - } - - if (InstantiateAtPOI.isInvalid()) - InstantiateAtPOI = Function->getLocation(); - } } if (InitFunctionInstantiation(Function, D)) @@ -1146,17 +1129,44 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, PrincipalDecl->setObjectOfFriendDecl(PrevDecl != 0); DC->makeDeclVisibleInContext(PrincipalDecl, /*Recoverable=*/ false); + + if (!SemaRef.getLangOptions().CPlusPlus0x && + D->isThisDeclarationADefinition()) { + // Check for a function body. + const FunctionDecl *Definition = 0; + if (Function->getBody(Definition) && + Definition->getTemplateSpecializationKind() == TSK_Undeclared) { + SemaRef.Diag(Function->getLocation(), diag::err_redefinition) + << Function->getDeclName(); + SemaRef.Diag(Definition->getLocation(), diag::note_previous_definition); + Function->setInvalidDecl(); + } + // Check for redefinitions due to other instantiations of this or + // a similar friend function. + else 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)) { + SemaRef.Diag(Function->getLocation(), diag::err_redefinition) + << Function->getDeclName(); + SemaRef.Diag((*R)->getLocation(), diag::note_previous_definition); + Function->setInvalidDecl(); + break; + } + } + } + } + } if (Function->isOverloadedOperator() && !DC->isRecord() && PrincipalDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary)) PrincipalDecl->setNonMemberOperator(); - // If we need to instantiate this function now (because it is a C++98/03 - // friend function defined inside a class template), do so. - if (InstantiateAtPOI.isValid()) - SemaRef.MarkDeclarationReferenced(InstantiateAtPOI, Function); - return Function; } @@ -1981,34 +1991,13 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, FunctionDecl *Function, bool Recursive, bool DefinitionRequired) { - if (Function->isInvalidDecl()) + if (Function->isInvalidDecl() || Function->getBody()) return; // Never instantiate an explicit specialization. if (Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) return; - const FunctionDecl *Definition = 0; - if (Function->getBody(Definition)) { - // We are trying to instantiate a friend function specialization inside - // a class template, but there is already another (non-template) definition - // of the same function. - if (Definition->getTemplateSpecializationKind() == TSK_Undeclared) { - InstantiatingTemplate Inst(*this, PointOfInstantiation, Function); - if (Inst) - return; - - 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. - return; - } - // Find the function body that we'll be substituting. const FunctionDecl *PatternDecl = Function->getTemplateInstantiationPattern(); Stmt *Pattern = 0; @@ -2035,32 +2024,6 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, 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/clang/test/CXX/class.access/class.friend/p1.cpp b/clang/test/CXX/class.access/class.friend/p1.cpp index e9177d44e7d9..563ae4f63c4d 100644 --- a/clang/test/CXX/class.access/class.friend/p1.cpp +++ b/clang/test/CXX/class.access/class.friend/p1.cpp @@ -188,8 +188,8 @@ namespace test4 { struct Inequal {}; bool test() { - Holder a, b; // expected-note {{requested here}} - return a == b; + Holder a, b; + return a == b; // expected-note {{requested here}} } } diff --git a/clang/test/CXX/temp/temp.decls/temp.friend/p4.cpp b/clang/test/CXX/temp/temp.decls/temp.friend/p4.cpp index e40872083399..226ac0fc622f 100644 --- a/clang/test/CXX/temp/temp.decls/temp.friend/p4.cpp +++ b/clang/test/CXX/temp/temp.decls/temp.friend/p4.cpp @@ -1,52 +1,10 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -template -struct X { - friend void f(int x) { T* y = x; } // expected-error{{cannot initialize a variable of type 'int *' with an lvalue of type 'int'}} -}; - -X xi; // expected-note{{in instantiation of member function 'f' requested here}} - -void f0(double) { } -void f0(int) { } // expected-note{{previous definition}} -void f1(int) { } // expected-note{{previous definition}} -void f2(int); -void f3(int); - template struct X1 { - friend void f0(T) { } // expected-error{{redefinition of}} - friend void f1(T) { } // expected-error{{redefinition of}} - friend void f2(T) { } // expected-error{{redefinition of}} - friend void f3(T) { } // expected-error{{redefinition of}} - friend void f4(T) { } // expected-error{{redefinition of}} - friend void f5(T) { } // expected-error{{redefinition of}} 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 7{{in instantiation of}} - -void f3(int) { } // expected-note{{previous definition}} -void f5(int) { } // expected-note{{previous definition}} - -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; +X1 x1a; +X1 x1b; // expected-note {{in instantiation of}}