forked from OSchip/llvm-project
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:
parent
061ca524b7
commit
b92ea59481
|
@ -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
|
||||
|
|
|
@ -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}}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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}}
|
||||
|
|
Loading…
Reference in New Issue