r304965 - Do not inherit default arguments for friend function in class template.

Serge Pavlov via cfe-commits cfe-commits at lists.llvm.org
Wed Jun 7 23:31:19 PDT 2017


Author: sepavloff
Date: Thu Jun  8 01:31:19 2017
New Revision: 304965

URL: http://llvm.org/viewvc/llvm-project?rev=304965&view=rev
Log:
Do not inherit default arguments for friend function in class template.

A function declared in a friend declaration may have declarations prior
to the containing class definition. If such declaration defines default
argument, the friend function declaration inherits them. This behavior
causes problems if the class where the friend is declared is a template:
during the class instantiation the friend function looks like if it had
default arguments, so error is triggered.

With this change friend functions declared in class templates do not
inherit default arguments. Actual set of them will be defined at the
point where the containing class is instantiated.

This change fixes PR12724.

Differential Revision: https://reviews.llvm.org/D30393

Modified:
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=304965&r1=304964&r2=304965&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Thu Jun  8 01:31:19 2017
@@ -547,17 +547,23 @@ bool Sema::MergeCXXFunctionDecl(Function
       Diag(OldParam->getLocation(), diag::note_previous_definition)
         << OldParam->getDefaultArgRange();
     } else if (OldParamHasDfl) {
-      // Merge the old default argument into the new parameter.
-      // It's important to use getInit() here;  getDefaultArg()
-      // strips off any top-level ExprWithCleanups.
-      NewParam->setHasInheritedDefaultArg();
-      if (OldParam->hasUnparsedDefaultArg())
-        NewParam->setUnparsedDefaultArg();
-      else if (OldParam->hasUninstantiatedDefaultArg())
-        NewParam->setUninstantiatedDefaultArg(
-                                      OldParam->getUninstantiatedDefaultArg());
-      else
-        NewParam->setDefaultArg(OldParam->getInit());
+      // Merge the old default argument into the new parameter unless the new
+      // function is a friend declaration in a template class. In the latter
+      // case the default arguments will be inherited when the friend
+      // declaration will be instantiated.
+      if (New->getFriendObjectKind() == Decl::FOK_None ||
+          !New->getLexicalDeclContext()->isDependentContext()) {
+        // It's important to use getInit() here;  getDefaultArg()
+        // strips off any top-level ExprWithCleanups.
+        NewParam->setHasInheritedDefaultArg();
+        if (OldParam->hasUnparsedDefaultArg())
+          NewParam->setUnparsedDefaultArg();
+        else if (OldParam->hasUninstantiatedDefaultArg())
+          NewParam->setUninstantiatedDefaultArg(
+                                       OldParam->getUninstantiatedDefaultArg());
+        else
+          NewParam->setDefaultArg(OldParam->getInit());
+      }
     } else if (NewParamHasDfl) {
       if (New->getDescribedFunctionTemplate()) {
         // Paragraph 4, quoted above, only applies to non-template functions.

Modified: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp?rev=304965&r1=304964&r2=304965&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp (original)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp Thu Jun  8 01:31:19 2017
@@ -73,3 +73,36 @@ void Test ()
 }
 
 } // namespace
+
+namespace pr12724 {
+
+void func_01(bool param = true);
+class C01 {
+public:
+  friend void func_01(bool param);
+};
+
+void func_02(bool param = true);
+template<typename T>
+class C02 {
+public:
+  friend void func_02(bool param);
+};
+C02<int> c02;
+
+void func_03(bool param);
+template<typename T>
+class C03 {
+public:
+  friend void func_03(bool param);
+};
+void func_03(bool param = true);
+C03<int> c03;
+
+void main() {
+  func_01();
+  func_02();
+  func_03();
+}
+
+} // namespace pr12724




More information about the cfe-commits mailing list