public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* C++ PATCH for c++/57728 (explicit instantiation and defaulted functions)
@ 2016-08-26 15:10 Jason Merrill
  2016-08-30 11:38 ` Rainer Orth
  0 siblings, 1 reply; 2+ messages in thread
From: Jason Merrill @ 2016-08-26 15:10 UTC (permalink / raw)
  To: gcc-patches List

[-- Attachment #1: Type: text/plain, Size: 719 bytes --]

The testcase in 57728 demonstrates that we have been treating
functions explicitly defaulted in the class body inconsistently with
explicit instantiation: an extern instantiation causes them not to be
generated, but a normal explicit instantiation doesn't cause them to
be emitted, leading to link errors.

After discussing this issue with other vendors (who had the same bug),
we have decided to treat these functions like implicitly declared
members, so explicit instantiation consistently doesn't affect them.

The second patch addresses a FIXME I noticed while looking at this:
there's no reason for us to be calling a trivial default constructor
in the first place.

Tested x86_64-pc-linux-gnu, applying to trunk.

[-- Attachment #2: 57728.diff --]
[-- Type: text/plain, Size: 2445 bytes --]

commit ec984d2d6e9258cfbf35d5198f4c4fc97fedf84e
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Aug 15 15:18:22 2016 -0400

    	PR c++/57728 - explicit instantiation and defaulted functions
    
    	* pt.c (do_type_instantiation): Don't mess with non-user-provided
    	member functions.

diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 3ad1b89..20689e4 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -5186,8 +5186,7 @@ in_class_defaulted_default_constructor (tree t)
 }
 
 /* Returns true iff FN is a user-provided function, i.e. user-declared
-   and not defaulted at its first declaration; or explicit, private,
-   protected, or non-const.  */
+   and not defaulted at its first declaration.  */
 
 bool
 user_provided_p (tree fn)
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 5d4f5ef..b0f0664 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -21479,7 +21479,8 @@ do_type_instantiation (tree t, tree storage, tsubst_flags_t complain)
     if (! static_p)
       for (tmp = TYPE_METHODS (t); tmp; tmp = DECL_CHAIN (tmp))
 	if (TREE_CODE (tmp) == FUNCTION_DECL
-	    && DECL_TEMPLATE_INSTANTIATION (tmp))
+	    && DECL_TEMPLATE_INSTANTIATION (tmp)
+	    && user_provided_p (tmp))
 	  instantiate_class_member (tmp, extern_p);
 
     for (tmp = TYPE_FIELDS (t); tmp; tmp = DECL_CHAIN (tmp))
diff --git a/gcc/testsuite/g++.dg/cpp0x/explicit11.C b/gcc/testsuite/g++.dg/cpp0x/explicit11.C
new file mode 100644
index 0000000..06d607f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/explicit11.C
@@ -0,0 +1,19 @@
+// Test that we treat defaulted-in-class members like implicitly declared
+// members for explicit instantiation.
+
+// { dg-do compile { target c++11 } }
+
+template<typename T>
+struct A
+{
+  T x;
+  A() = default;
+  A(const A &other) = default;
+  A& operator=(const A&) = default;
+};
+
+template class A<int>;
+
+// { dg-final { scan-assembler-not "_ZN1AIiEC1Ev" } }
+// { dg-final { scan-assembler-not "_ZN1AIiEC1ERKS0_" } }
+// { dg-final { scan-assembler-not "_ZN1AIiEaSERKS0_" } }
diff --git a/gcc/testsuite/g++.dg/cpp0x/explicit12.C b/gcc/testsuite/g++.dg/cpp0x/explicit12.C
new file mode 100644
index 0000000..5c14c01
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/explicit12.C
@@ -0,0 +1,17 @@
+// PR c++/57728
+// { dg-do link { target c++11 } }
+
+template<typename T>
+struct A
+{
+  T x;
+  A() = default;
+  A(const A &other) = delete;
+};
+
+extern template class A<int>;
+
+int main()
+{
+  A<int> a;
+}

[-- Attachment #3: trivial-df.diff --]
[-- Type: text/plain, Size: 4006 bytes --]

commit 4d2423235cc1f701fa23a66b82739b166d4df6a1
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Aug 15 15:25:34 2016 -0400

    	Avoid calling a trivial default constructor.
    
    	* class.c (default_ctor_p): New.
    	(in_class_defaulted_default_constructor): Use it.
    	(type_has_non_user_provided_default_constructor): Use it.
    	* call.c (build_over_call): Handle trivial default constructor.
    	* cp-tree.h: Declare default_ctor_p.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 05f0431..024519d 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -7798,11 +7798,19 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
 
       return val;
     }
-  else if (DECL_DESTRUCTOR_P (fn)
-	   && trivial_fn_p (fn)
-	   && !DECL_DELETED_FN (fn))
-    return fold_convert (void_type_node, argarray[0]);
-  /* FIXME handle trivial default constructor, too.  */
+  else if (!DECL_DELETED_FN (fn)
+	   && trivial_fn_p (fn))
+    {
+      if (DECL_DESTRUCTOR_P (fn))
+	return fold_convert (void_type_node, argarray[0]);
+      else if (default_ctor_p (fn))
+	{
+	  if (is_dummy_object (argarray[0]))
+	    return force_target_expr (DECL_CONTEXT (fn), void_node, complain);
+	  else
+	    return cp_build_indirect_ref (argarray[0], RO_NULL, complain);
+	}
+    }
 
   /* For calls to a multi-versioned function, overload resolution
      returns the function with the highest target priority, that is,
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 20689e4..a4f3c6b 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -5133,8 +5133,17 @@ set_method_tm_attributes (tree t)
     }
 }
 
-/* Returns true iff class T has a user-defined constructor other than
-   the default constructor.  */
+/* Returns true if FN is a default constructor.  */
+
+bool
+default_ctor_p (tree fn)
+{
+  return (DECL_CONSTRUCTOR_P (fn)
+	  && sufficient_parms_p (FUNCTION_FIRST_USER_PARMTYPE (fn)));
+}
+
+/* Returns true iff class T has a user-defined constructor that can be called
+   with more than zero arguments.  */
 
 bool
 type_has_user_nondefault_constructor (tree t)
@@ -5163,23 +5172,16 @@ type_has_user_nondefault_constructor (tree t)
 tree
 in_class_defaulted_default_constructor (tree t)
 {
-  tree fns, args;
-
   if (!TYPE_HAS_USER_CONSTRUCTOR (t))
     return NULL_TREE;
 
-  for (fns = CLASSTYPE_CONSTRUCTORS (t); fns; fns = OVL_NEXT (fns))
+  for (tree fns = CLASSTYPE_CONSTRUCTORS (t); fns; fns = OVL_NEXT (fns))
     {
       tree fn = OVL_CURRENT (fns);
 
-      if (DECL_DEFAULTED_IN_CLASS_P (fn))
-	{
-	  args = FUNCTION_FIRST_USER_PARMTYPE (fn);
-	  while (args && TREE_PURPOSE (args))
-	    args = TREE_CHAIN (args);
-	  if (!args || args == void_list_node)
-	    return fn;
-	}
+      if (DECL_DEFAULTED_IN_CLASS_P (fn)
+	  && default_ctor_p (fn))
+	return fn;
     }
 
   return NULL_TREE;
@@ -5268,8 +5270,8 @@ type_has_non_user_provided_default_constructor (tree t)
     {
       tree fn = OVL_CURRENT (fns);
       if (TREE_CODE (fn) == FUNCTION_DECL
-	  && !user_provided_p (fn)
-	  && sufficient_parms_p (FUNCTION_FIRST_USER_PARMTYPE (fn)))
+	  && default_ctor_p (fn)
+	  && !user_provided_p (fn))
 	return true;
     }
 
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 8a32f17..72a128d 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5666,6 +5666,7 @@ extern void determine_key_method		(tree);
 extern void check_for_override			(tree, tree);
 extern void push_class_stack			(void);
 extern void pop_class_stack			(void);
+extern bool default_ctor_p			(tree);
 extern bool type_has_user_nondefault_constructor (tree);
 extern tree in_class_defaulted_default_constructor (tree);
 extern bool user_provided_p			(tree);
diff --git a/gcc/testsuite/g++.dg/cpp0x/explicit12.C b/gcc/testsuite/g++.dg/cpp0x/explicit12.C
index 5c14c01..912d507 100644
--- a/gcc/testsuite/g++.dg/cpp0x/explicit12.C
+++ b/gcc/testsuite/g++.dg/cpp0x/explicit12.C
@@ -15,3 +15,5 @@ int main()
 {
   A<int> a;
 }
+
+// { dg-final { scan-assembler-not "_ZN1AIiEC1Ev" } }

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: C++ PATCH for c++/57728 (explicit instantiation and defaulted functions)
  2016-08-26 15:10 C++ PATCH for c++/57728 (explicit instantiation and defaulted functions) Jason Merrill
@ 2016-08-30 11:38 ` Rainer Orth
  0 siblings, 0 replies; 2+ messages in thread
From: Rainer Orth @ 2016-08-30 11:38 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches List

Hi Jason,

> The testcase in 57728 demonstrates that we have been treating
> functions explicitly defaulted in the class body inconsistently with
> explicit instantiation: an extern instantiation causes them not to be
> generated, but a normal explicit instantiation doesn't cause them to
> be emitted, leading to link errors.
>
> After discussing this issue with other vendors (who had the same bug),
> we have decided to treat these functions like implicitly declared
> members, so explicit instantiation consistently doesn't affect them.
>
> The second patch addresses a FIXME I noticed while looking at this:
> there's no reason for us to be calling a trivial default constructor
> in the first place.
>
> Tested x86_64-pc-linux-gnu, applying to trunk.
[...]
> diff --git a/gcc/testsuite/g++.dg/cpp0x/explicit12.C b/gcc/testsuite/g++.dg/cpp0x/explicit12.C
> new file mode 100644
> index 0000000..5c14c01
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/explicit12.C
> @@ -0,0 +1,17 @@
> +// PR c++/57728
> +// { dg-do link { target c++11 } }
[...]
> diff --git a/gcc/testsuite/g++.dg/cpp0x/explicit12.C b/gcc/testsuite/g++.dg/cpp0x/explicit12.C
> index 5c14c01..912d507 100644
> --- a/gcc/testsuite/g++.dg/cpp0x/explicit12.C
> +++ b/gcc/testsuite/g++.dg/cpp0x/explicit12.C
> @@ -15,3 +15,5 @@ int main()
>  {
>    A<int> a;
>  }
> +
> +// { dg-final { scan-assembler-not "_ZN1AIiEC1Ev" } }
>

This test currently shows up as UNRESOLVED, and g++.log has

g++.dg/cpp0x/explicit12.C  -std=c++11 : output file does not exist

Was this meant as a compile instead of link test, like the companion
explicit11.C?

	Rainer

-- 
-----------------------------------------------------------------------------
Rainer Orth, Center for Biotechnology, Bielefeld University

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2016-08-30 11:38 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-08-26 15:10 C++ PATCH for c++/57728 (explicit instantiation and defaulted functions) Jason Merrill
2016-08-30 11:38 ` Rainer Orth

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).