Implement DR329. We already did the right thing here in C++98 mode, but r104014

(which implemented the DR) was disabled in C++11.

llvm-svn: 200673
This commit is contained in:
Richard Smith 2014-02-03 02:37:59 +00:00
parent 9f38709193
commit 91dfaacd38
6 changed files with 40 additions and 82 deletions

View File

@ -3586,9 +3586,6 @@ def err_definition_of_explicitly_defaulted_member : Error<
def err_redefinition_extern_inline : Error< def err_redefinition_extern_inline : Error<
"redefinition of a 'extern inline' function %0 is not supported in " "redefinition of a 'extern inline' function %0 is not supported in "
"%select{C99 mode|C++}1">; "%select{C99 mode|C++}1">;
def warn_cxx98_compat_friend_redefinition : Warning<
"friend function %0 would be implicitly redefined in C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def note_deleted_dtor_no_operator_delete : Note< def note_deleted_dtor_no_operator_delete : Note<
"virtual destructor requires an unambiguous, accessible 'operator delete'">; "virtual destructor requires an unambiguous, accessible 'operator delete'">;

View File

@ -1225,7 +1225,6 @@ static QualType adjustFunctionTypeForInstantiation(ASTContext &Context,
/// don't make it here. This function serves two purposes: /// don't make it here. This function serves two purposes:
/// 1) instantiating function templates /// 1) instantiating function templates
/// 2) substituting friend declarations /// 2) substituting friend declarations
/// FIXME: preserve function definitions in case #2
Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
TemplateParameterList *TemplateParams) { TemplateParameterList *TemplateParams) {
// Check whether there is already a function template specialization for // Check whether there is already a function template specialization for
@ -1435,35 +1434,22 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
PrincipalDecl->setObjectOfFriendDecl(); PrincipalDecl->setObjectOfFriendDecl();
DC->makeDeclVisibleInContext(PrincipalDecl); DC->makeDeclVisibleInContext(PrincipalDecl);
bool queuedInstantiation = false; bool QueuedInstantiation = false;
// C++98 [temp.friend]p5: When a function is defined in a friend function // C++11 [temp.friend]p4 (DR329):
// declaration in a class template, the function is defined at each // When a function is defined in a friend function declaration in a class
// instantiation of the class template. The function is defined even if it // template, the function is instantiated when the function is odr-used.
// is never used. // The same restrictions on multiple declarations and definitions that
// C++11 [temp.friend]p4: When a function is defined in a friend function // apply to non-template function declarations and definitions also apply
// declaration in a class template, the function is instantiated when the // to these implicit definitions.
// function is odr-used. if (D->isThisDeclarationADefinition()) {
//
// If -Wc++98-compat is enabled, we go through the motions of checking for a
// redefinition, but don't instantiate the function.
if ((!SemaRef.getLangOpts().CPlusPlus11 ||
SemaRef.Diags.getDiagnosticLevel(
diag::warn_cxx98_compat_friend_redefinition,
Function->getLocation())
!= DiagnosticsEngine::Ignored) &&
D->isThisDeclarationADefinition()) {
// Check for a function body. // Check for a function body.
const FunctionDecl *Definition = 0; const FunctionDecl *Definition = 0;
if (Function->isDefined(Definition) && if (Function->isDefined(Definition) &&
Definition->getTemplateSpecializationKind() == TSK_Undeclared) { Definition->getTemplateSpecializationKind() == TSK_Undeclared) {
SemaRef.Diag(Function->getLocation(), SemaRef.Diag(Function->getLocation(), diag::err_redefinition)
SemaRef.getLangOpts().CPlusPlus11 ? << Function->getDeclName();
diag::warn_cxx98_compat_friend_redefinition :
diag::err_redefinition) << Function->getDeclName();
SemaRef.Diag(Definition->getLocation(), diag::note_previous_definition); SemaRef.Diag(Definition->getLocation(), diag::note_previous_definition);
if (!SemaRef.getLangOpts().CPlusPlus11)
Function->setInvalidDecl();
} }
// Check for redefinitions due to other instantiations of this or // Check for redefinitions due to other instantiations of this or
// a similar friend function. // a similar friend function.
@ -1472,36 +1458,34 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
R != REnd; ++R) { R != REnd; ++R) {
if (*R == Function) if (*R == Function)
continue; continue;
switch (R->getFriendObjectKind()) {
case Decl::FOK_None: // If some prior declaration of this function has been used, we need
if (!SemaRef.getLangOpts().CPlusPlus11 && // to instantiate its definition.
!queuedInstantiation && R->isUsed(false)) { if (!QueuedInstantiation && R->isUsed(false)) {
if (MemberSpecializationInfo *MSInfo if (MemberSpecializationInfo *MSInfo =
= Function->getMemberSpecializationInfo()) { Function->getMemberSpecializationInfo()) {
if (MSInfo->getPointOfInstantiation().isInvalid()) { if (MSInfo->getPointOfInstantiation().isInvalid()) {
SourceLocation Loc = R->getLocation(); // FIXME SourceLocation Loc = R->getLocation(); // FIXME
MSInfo->setPointOfInstantiation(Loc); MSInfo->setPointOfInstantiation(Loc);
SemaRef.PendingLocalImplicitInstantiations.push_back( SemaRef.PendingLocalImplicitInstantiations.push_back(
std::make_pair(Function, Loc)); std::make_pair(Function, Loc));
queuedInstantiation = true; QueuedInstantiation = true;
}
} }
} }
break; }
default:
if (const FunctionDecl *RPattern // If some prior declaration of this function was a friend with an
= R->getTemplateInstantiationPattern()) // uninstantiated definition, reject it.
if (R->getFriendObjectKind()) {
if (const FunctionDecl *RPattern =
R->getTemplateInstantiationPattern()) {
if (RPattern->isDefined(RPattern)) { if (RPattern->isDefined(RPattern)) {
SemaRef.Diag(Function->getLocation(), SemaRef.Diag(Function->getLocation(), diag::err_redefinition)
SemaRef.getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_friend_redefinition :
diag::err_redefinition)
<< Function->getDeclName(); << Function->getDeclName();
SemaRef.Diag(R->getLocation(), diag::note_previous_definition); SemaRef.Diag(R->getLocation(), diag::note_previous_definition);
if (!SemaRef.getLangOpts().CPlusPlus11)
Function->setInvalidDecl();
break; break;
} }
}
} }
} }
} }

View File

@ -464,23 +464,15 @@ namespace dr46 { // dr46: yes
template template struct A<int>::B<int>; // expected-error {{expected unqualified-id}} template template struct A<int>::B<int>; // expected-error {{expected unqualified-id}}
} }
namespace dr47 { // dr47: no namespace dr47 { // dr47: sup 329
template<typename T> struct A { template<typename T> struct A {
friend void f() { T t; } friend void f() { T t; } // expected-error {{redefinition}} expected-note {{previous}}
}; };
A<int> a; A<int> a;
A<float> b; A<float> b; // expected-note {{instantiation of}}
#if __cplusplus < 201103L
// expected-error@-5 {{redefinition}} expected-note@-5 {{previous}}
// expected-note@-3 {{instantiation of}}
#else
void f(); void f();
// FIXME: We should produce some kind of error here. C++11 [temp.friend]p4
// says we instantiate 'f' when it's odr-used, but that doesn't imply that
// this is valid; we still have multiple definitions of 'f' even if we never
// instantiate any of them.
void g() { f(); } void g() { f(); }
#endif
} }
namespace dr48 { // dr48: yes namespace dr48 { // dr48: yes

View File

@ -316,25 +316,17 @@ namespace dr328 { // dr328: yes
A *p = new A[0]; // expected-error {{incomplete}} A *p = new A[0]; // expected-error {{incomplete}}
} }
namespace dr329 { // dr329: no namespace dr329 { // dr329: 3.5
// FIXME: The C++98 behavior here is right, the C++11-onwards behavior
// is wrong.
struct B {}; struct B {};
template<typename T> struct A : B { template<typename T> struct A : B {
friend void f(A a) { g(a); } friend void f(A a) { g(a); }
friend void h(A a) { g(a); } // expected-error {{undeclared}} friend void h(A a) { g(a); } // expected-error {{undeclared}}
friend void i(B b) {} friend void i(B b) {} // expected-error {{redefinition}} expected-note {{previous}}
}; };
A<int> a; A<int> a;
A<char> b; A<char> b; // expected-note {{instantiation}}
#if __cplusplus < 201103L
// expected-error@-5 {{redefinition}} expected-note@-5 {{previous}}
// expected-note@-3 {{instantiation}}
#endif
void test() { void test() {
h(a); // expected-note {{instantiation}} h(a); // expected-note {{instantiation}}
i(a);
i(b);
} }
} }

View File

@ -225,13 +225,6 @@ template<typename T> typename T::ImPrivate SFINAEAccessControl(T t) { // expecte
int SFINAEAccessControl(...) { return 0; } int SFINAEAccessControl(...) { return 0; }
int CheckSFINAEAccessControl = SFINAEAccessControl(PrivateMember()); // expected-note {{while substituting deduced template arguments into function template 'SFINAEAccessControl' [with T = PrivateMember]}} int CheckSFINAEAccessControl = SFINAEAccessControl(PrivateMember()); // expected-note {{while substituting deduced template arguments into function template 'SFINAEAccessControl' [with T = PrivateMember]}}
template<typename T>
struct FriendRedefinition {
friend void Friend() {} // expected-warning {{friend function 'Friend' would be implicitly redefined in C++98}} expected-note {{previous}}
};
FriendRedefinition<int> FriendRedef1;
FriendRedefinition<char> FriendRedef2; // expected-note {{requested here}}
namespace CopyCtorIssues { namespace CopyCtorIssues {
struct Private { struct Private {
Private(); Private();

View File

@ -321,7 +321,7 @@
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#47">47</a></td> <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#47">47</a></td>
<td>NAD</td> <td>NAD</td>
<td>Template friend issues</td> <td>Template friend issues</td>
<td class="none" align="center">No</td> <td class="svn" align="center">Superseded by 329</td>
</tr> </tr>
<tr> <tr>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#48">48</a></td> <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#48">48</a></td>
@ -2015,7 +2015,7 @@ of class templates</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#329">329</a></td> <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#329">329</a></td>
<td>CD1</td> <td>CD1</td>
<td>Evaluation of friends of templates</td> <td>Evaluation of friends of templates</td>
<td class="none" align="center">No</td> <td class="svn" align="center">SVN</td>
</tr> </tr>
<tr class="open"> <tr class="open">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#330">330</a></td> <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#330">330</a></td>