[cfe-commits] r104014 - in /cfe/trunk: lib/Sema/SemaTemplateInstantiateDecl.cpp test/CXX/class.access/class.friend/p1.cpp test/CXX/temp/temp.decls/temp.friend/p4.cpp
Douglas Gregor
dgregor at apple.com
Mon May 17 22:45:02 PDT 2010
Author: dgregor
Date: Tue May 18 00:45:02 2010
New Revision: 104014
URL: http://llvm.org/viewvc/llvm-project?rev=104014&view=rev
Log:
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.
Modified:
cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
cfe/trunk/test/CXX/class.access/class.friend/p1.cpp
cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p4.cpp
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=104014&r1=104013&r2=104014&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Tue May 18 00:45:02 2010
@@ -1049,23 +1049,6 @@
// 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 @@
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 @@
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 @@
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
Modified: cfe/trunk/test/CXX/class.access/class.friend/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class.access/class.friend/p1.cpp?rev=104014&r1=104013&r2=104014&view=diff
==============================================================================
--- cfe/trunk/test/CXX/class.access/class.friend/p1.cpp (original)
+++ cfe/trunk/test/CXX/class.access/class.friend/p1.cpp Tue May 18 00:45:02 2010
@@ -188,8 +188,8 @@
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}}
}
}
Modified: cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p4.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p4.cpp?rev=104014&r1=104013&r2=104014&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p4.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p4.cpp Tue May 18 00:45:02 2010
@@ -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}}
More information about the cfe-commits
mailing list