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

Richard Smith richard-llvm at metafoo.co.uk
Sun Feb 2 18:38:00 PST 2014


Author: rsmith
Date: Sun Feb  2 20:37:59 2014
New Revision: 200673

URL: http://llvm.org/viewvc/llvm-project?rev=200673&view=rev
Log:
Implement DR329. We already did the right thing here in C++98 mode, but r104014
(which implemented the DR) was disabled in C++11.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/test/CXX/drs/dr0xx.cpp
    cfe/trunk/test/CXX/drs/dr3xx.cpp
    cfe/trunk/test/SemaCXX/cxx98-compat.cpp
    cfe/trunk/www/cxx_dr_status.html

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=200673&r1=200672&r2=200673&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Sun Feb  2 20:37:59 2014
@@ -3586,9 +3586,6 @@ def err_definition_of_explicitly_default
 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;
 
 def note_deleted_dtor_no_operator_delete : Note<
   "virtual destructor requires an unambiguous, accessible 'operator delete'">;

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=200673&r1=200672&r2=200673&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Sun Feb  2 20:37:59 2014
@@ -1225,7 +1225,6 @@ static QualType adjustFunctionTypeForIns
 /// don't make it here.  This function serves two purposes:
 ///   1) instantiating function templates
 ///   2) substituting friend declarations
-/// FIXME: preserve function definitions in case #2
 Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
                                        TemplateParameterList *TemplateParams) {
   // Check whether there is already a function template specialization for
@@ -1435,35 +1434,22 @@ Decl *TemplateDeclInstantiator::VisitFun
     PrincipalDecl->setObjectOfFriendDecl();
     DC->makeDeclVisibleInContext(PrincipalDecl);
 
-    bool queuedInstantiation = false;
+    bool QueuedInstantiation = false;
 
-    // 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.getLangOpts().CPlusPlus11 ||
-         SemaRef.Diags.getDiagnosticLevel(
-             diag::warn_cxx98_compat_friend_redefinition,
-             Function->getLocation())
-           != DiagnosticsEngine::Ignored) &&
-        D->isThisDeclarationADefinition()) {
+    // C++11 [temp.friend]p4 (DR329):
+    //   When a function is defined in a friend function declaration in a class
+    //   template, the function is instantiated when the function is odr-used.
+    //   The same restrictions on multiple declarations and definitions that
+    //   apply to non-template function declarations and definitions also apply
+    //   to these implicit definitions.
+    if (D->isThisDeclarationADefinition()) {
       // Check for a function body.
       const FunctionDecl *Definition = 0;
       if (Function->isDefined(Definition) &&
           Definition->getTemplateSpecializationKind() == TSK_Undeclared) {
-        SemaRef.Diag(Function->getLocation(),
-                     SemaRef.getLangOpts().CPlusPlus11 ?
-                       diag::warn_cxx98_compat_friend_redefinition :
-                       diag::err_redefinition) << Function->getDeclName();
+        SemaRef.Diag(Function->getLocation(), diag::err_redefinition)
+            << Function->getDeclName();
         SemaRef.Diag(Definition->getLocation(), diag::note_previous_definition);
-        if (!SemaRef.getLangOpts().CPlusPlus11)
-          Function->setInvalidDecl();
       }
       // Check for redefinitions due to other instantiations of this or
       // a similar friend function.
@@ -1472,36 +1458,34 @@ Decl *TemplateDeclInstantiator::VisitFun
                 R != REnd; ++R) {
         if (*R == Function)
           continue;
-        switch (R->getFriendObjectKind()) {
-        case Decl::FOK_None:
-          if (!SemaRef.getLangOpts().CPlusPlus11 &&
-              !queuedInstantiation && R->isUsed(false)) {
-            if (MemberSpecializationInfo *MSInfo
-                = Function->getMemberSpecializationInfo()) {
-              if (MSInfo->getPointOfInstantiation().isInvalid()) {
-                SourceLocation Loc = R->getLocation(); // FIXME
-                MSInfo->setPointOfInstantiation(Loc);
-                SemaRef.PendingLocalImplicitInstantiations.push_back(
-                                                 std::make_pair(Function, Loc));
-                queuedInstantiation = true;
-              }
+
+        // If some prior declaration of this function has been used, we need
+        // to instantiate its definition.
+        if (!QueuedInstantiation && R->isUsed(false)) {
+          if (MemberSpecializationInfo *MSInfo =
+                  Function->getMemberSpecializationInfo()) {
+            if (MSInfo->getPointOfInstantiation().isInvalid()) {
+              SourceLocation Loc = R->getLocation(); // FIXME
+              MSInfo->setPointOfInstantiation(Loc);
+              SemaRef.PendingLocalImplicitInstantiations.push_back(
+                                               std::make_pair(Function, Loc));
+              QueuedInstantiation = true;
             }
           }
-          break;
-        default:
-          if (const FunctionDecl *RPattern
-              = R->getTemplateInstantiationPattern())
+        }
+
+        // If some prior declaration of this function was a friend with an
+        // uninstantiated definition, reject it.
+        if (R->getFriendObjectKind()) {
+          if (const FunctionDecl *RPattern =
+                  R->getTemplateInstantiationPattern()) {
             if (RPattern->isDefined(RPattern)) {
-              SemaRef.Diag(Function->getLocation(),
-                           SemaRef.getLangOpts().CPlusPlus11 ?
-                             diag::warn_cxx98_compat_friend_redefinition :
-                             diag::err_redefinition)
+              SemaRef.Diag(Function->getLocation(), diag::err_redefinition)
                 << Function->getDeclName();
               SemaRef.Diag(R->getLocation(), diag::note_previous_definition);
-              if (!SemaRef.getLangOpts().CPlusPlus11)
-                Function->setInvalidDecl();
               break;
             }
+          }
         }
       }
     }

Modified: cfe/trunk/test/CXX/drs/dr0xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr0xx.cpp?rev=200673&r1=200672&r2=200673&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr0xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr0xx.cpp Sun Feb  2 20:37:59 2014
@@ -464,23 +464,15 @@ namespace dr46 { // dr46: yes
   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 {
-    friend void f() { T t; }
+    friend void f() { T t; } // expected-error {{redefinition}} expected-note {{previous}}
   };
   A<int> a;
-  A<float> b;
-#if __cplusplus < 201103L
-  // expected-error at -5 {{redefinition}} expected-note at -5 {{previous}}
-  // expected-note at -3 {{instantiation of}}
-#else
+  A<float> b; // expected-note {{instantiation of}}
+
   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(); }
-#endif
 }
 
 namespace dr48 { // dr48: yes

Modified: cfe/trunk/test/CXX/drs/dr3xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr3xx.cpp?rev=200673&r1=200672&r2=200673&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr3xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr3xx.cpp Sun Feb  2 20:37:59 2014
@@ -316,25 +316,17 @@ namespace dr328 { // dr328: yes
   A *p = new A[0]; // expected-error {{incomplete}}
 }
 
-namespace dr329 { // dr329: no
-  // FIXME: The C++98 behavior here is right, the C++11-onwards behavior
-  // is wrong.
+namespace dr329 { // dr329: 3.5
   struct B {};
   template<typename T> struct A : B {
     friend void f(A a) { g(a); }
     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<char> b;
-#if __cplusplus < 201103L
-  // expected-error at -5 {{redefinition}} expected-note at -5 {{previous}}
-  // expected-note at -3 {{instantiation}}
-#endif
+  A<char> b; // expected-note {{instantiation}}
 
   void test() {
     h(a); // expected-note {{instantiation}}
-    i(a);
-    i(b);
   }
 }

Modified: cfe/trunk/test/SemaCXX/cxx98-compat.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx98-compat.cpp?rev=200673&r1=200672&r2=200673&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx98-compat.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx98-compat.cpp Sun Feb  2 20:37:59 2014
@@ -225,13 +225,6 @@ template<typename T> typename T::ImPriva
 int SFINAEAccessControl(...) { return 0; }
 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 {
   struct Private {
     Private();

Modified: cfe/trunk/www/cxx_dr_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_dr_status.html?rev=200673&r1=200672&r2=200673&view=diff
==============================================================================
--- cfe/trunk/www/cxx_dr_status.html (original)
+++ cfe/trunk/www/cxx_dr_status.html Sun Feb  2 20:37:59 2014
@@ -321,7 +321,7 @@
     <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#47">47</a></td>
     <td>NAD</td>
     <td>Template friend issues</td>
-    <td class="none" align="center">No</td>
+    <td class="svn" align="center">Superseded by 329</td>
   </tr>
   <tr>
     <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>CD1</td>
     <td>Evaluation of friends of templates</td>
-    <td class="none" align="center">No</td>
+    <td class="svn" align="center">SVN</td>
   </tr>
   <tr class="open">
     <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#330">330</a></td>





More information about the cfe-commits mailing list