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
This commit is contained in:
Douglas Gregor 2010-05-18 05:45:02 +00:00
parent 061ca524b7
commit b92ea59481
3 changed files with 37 additions and 116 deletions

View File

@ -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<CXXRecordDecl>(Owner)) {
if (ClassTemplateSpecializationDecl *Spec
= dyn_cast<ClassTemplateSpecializationDecl>(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

View File

@ -188,8 +188,8 @@ namespace test4 {
struct Inequal {};
bool test() {
Holder<Inequal> a, b; // expected-note {{requested here}}
return a == b;
Holder<Inequal> a, b;
return a == b; // expected-note {{requested here}}
}
}

View File

@ -1,52 +1,10 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
template<typename T>
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<int> 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<typename T>
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<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<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;
X1<int> x1a;
X1<float> x1b; // expected-note {{in instantiation of}}