From: Richard Smith Date: Wed, 19 Oct 2011 00:54:10 +0000 (+0000) Subject: Add a -Wc++98-compat warning for friend functions of class templates which would X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=53e535161dfa9850de394b300915fc250eb0fdf4;p=clang Add a -Wc++98-compat warning for friend functions of class templates which would be implicitly instantiated (resulting in a redefinition) in C++98. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@142468 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 5c4ecc8f9d..e5a49c658a 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2652,6 +2652,9 @@ def err_definition_of_explicitly_defaulted_member : Error< def err_redefinition_extern_inline : Error< "redefinition of a 'extern inline' function %0 is not supported in " "%select{C99 mode|C++}1">; +def warn_cxx98_compat_friend_redefinition : Warning< + "friend function %0 would be implicitly redefined in C++98">, + InGroup, DefaultIgnore; // This should eventually be an error. def warn_undefined_internal : Warning< diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 02a05d5182..218beaa682 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1230,16 +1230,33 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, bool queuedInstantiation = false; - if (!SemaRef.getLangOptions().CPlusPlus0x && + // C++98 [temp.friend]p5: 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. + // C++11 [temp.friend]p4: When a function is defined in a friend function + // declaration in a class template, the function is instantiated when the + // function is odr-used. + // + // If -Wc++98-compat is enabled, we go through the motions of checking for a + // redefinition, but don't instantiate the function. + if ((!SemaRef.getLangOptions().CPlusPlus0x || + SemaRef.Diags.getDiagnosticLevel( + diag::warn_cxx98_compat_friend_redefinition, + Function->getLocation()) + != DiagnosticsEngine::Ignored) && D->isThisDeclarationADefinition()) { // Check for a function body. const FunctionDecl *Definition = 0; if (Function->isDefined(Definition) && Definition->getTemplateSpecializationKind() == TSK_Undeclared) { - SemaRef.Diag(Function->getLocation(), diag::err_redefinition) - << Function->getDeclName(); + SemaRef.Diag(Function->getLocation(), + SemaRef.getLangOptions().CPlusPlus0x ? + diag::warn_cxx98_compat_friend_redefinition : + diag::err_redefinition) << Function->getDeclName(); SemaRef.Diag(Definition->getLocation(), diag::note_previous_definition); - Function->setInvalidDecl(); + if (!SemaRef.getLangOptions().CPlusPlus0x) + Function->setInvalidDecl(); } // Check for redefinitions due to other instantiations of this or // a similar friend function. @@ -1250,7 +1267,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, continue; switch (R->getFriendObjectKind()) { case Decl::FOK_None: - if (!queuedInstantiation && R->isUsed(false)) { + if (!SemaRef.getLangOptions().CPlusPlus0x && + !queuedInstantiation && R->isUsed(false)) { if (MemberSpecializationInfo *MSInfo = Function->getMemberSpecializationInfo()) { if (MSInfo->getPointOfInstantiation().isInvalid()) { @@ -1267,10 +1285,14 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, if (const FunctionDecl *RPattern = R->getTemplateInstantiationPattern()) if (RPattern->isDefined(RPattern)) { - SemaRef.Diag(Function->getLocation(), diag::err_redefinition) + SemaRef.Diag(Function->getLocation(), + SemaRef.getLangOptions().CPlusPlus0x ? + diag::warn_cxx98_compat_friend_redefinition : + diag::err_redefinition) << Function->getDeclName(); SemaRef.Diag(R->getLocation(), diag::note_previous_definition); - Function->setInvalidDecl(); + if (!SemaRef.getLangOptions().CPlusPlus0x) + Function->setInvalidDecl(); break; } } diff --git a/test/SemaCXX/cxx98-compat.cpp b/test/SemaCXX/cxx98-compat.cpp index 8da54f0da6..193a418d7f 100644 --- a/test/SemaCXX/cxx98-compat.cpp +++ b/test/SemaCXX/cxx98-compat.cpp @@ -179,3 +179,10 @@ template typename T::ImPrivate SFINAEAccessControl(T t) { // expecte } int SFINAEAccessControl(...) { return 0; } int CheckSFINAEAccessControl = SFINAEAccessControl(PrivateMember()); + +template +struct FriendRedefinition { + friend void Friend() {} // expected-warning {{friend function 'Friend' would be implicitly redefined in C++98}} expected-note {{previous}} +}; +FriendRedefinition FriendRedef1; +FriendRedefinition FriendRedef2; // expected-note {{requested here}}