[cfe-commits] r142468 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/SemaTemplateInstantiateDecl.cpp test/SemaCXX/cxx98-compat.cpp

Richard Smith richard-llvm at metafoo.co.uk
Tue Oct 18 17:54:10 PDT 2011


Author: rsmith
Date: Tue Oct 18 19:54:10 2011
New Revision: 142468

URL: http://llvm.org/viewvc/llvm-project?rev=142468&view=rev
Log:
Add a -Wc++98-compat warning for friend functions of class templates which would
be implicitly instantiated (resulting in a redefinition) in C++98.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/test/SemaCXX/cxx98-compat.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=142468&r1=142467&r2=142468&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Oct 18 19:54:10 2011
@@ -2652,6 +2652,9 @@
 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<

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=142468&r1=142467&r2=142468&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Tue Oct 18 19:54:10 2011
@@ -1230,16 +1230,33 @@
 
     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 @@
           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 @@
           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;
             }
         }

Modified: cfe/trunk/test/SemaCXX/cxx98-compat.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx98-compat.cpp?rev=142468&r1=142467&r2=142468&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx98-compat.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx98-compat.cpp Tue Oct 18 19:54:10 2011
@@ -179,3 +179,10 @@
 }
 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}}





More information about the cfe-commits mailing list