diff options
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 3 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 36 | ||||
-rw-r--r-- | test/SemaCXX/cxx98-compat.cpp | 7 |
3 files changed, 39 insertions, 7 deletions
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<CXX98Compat>, 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> typename T::ImPrivate SFINAEAccessControl(T t) { // expecte } int SFINAEAccessControl(...) { return 0; } int CheckSFINAEAccessControl = SFINAEAccessControl(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}} |