summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td3
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp36
-rw-r--r--test/SemaCXX/cxx98-compat.cpp7
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}}