Patchwork C++ PATCH for c++/46807 (ICE with synthesized ctor and mutable)

login
register
mail settings
Submitter Jason Merrill
Date Feb. 16, 2011, 12:39 a.m.
Message ID <4D5B1CC8.5000303@redhat.com>
Download mbox | patch
Permalink /patch/83320/
State New
Headers show

Comments

Jason Merrill - Feb. 16, 2011, 12:39 a.m.
So, in 4.6 I've started using overload resolution early to determine 
what constructor will actually be called by a synthesized constructor in 
order to determine the right exception specification for it.  In C++0x 
mode this can also affect the triviality of the function.  But in 
C++98/03, triviality is not specified in terms of what base constructor 
would be called, but just whether the base has a trivial copy 
constructor.  This is not terribly consistent, but changing it at this 
point could cause trouble with existing code.

Previously I had been thinking that the overload resolution would always 
give the same answer as the determination based on simple analysis of 
the copy constructor; this PR demonstrated that this was wrong.  So in 
C++98 mode we always exit early if the simple analysis decided that the 
function is trivial; we choose to respect that even if it would differ 
from the full analysis.  This preserves the behavior of previous 
compiler versions in C++98 mode.

Tested x86_64-pc-linux-gnu, applied to trunk.
commit 2fd22fda4391675ca08f73223ebfaeaa302561c2
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Feb 14 17:34:47 2011 -0500

    	PR c++/46807
    	* method.c (synthesized_method_walk): Always exit early for
    	trivial fn in C++98 mode.

Patch

diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 3f0baed..bfe8a06 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -1153,13 +1153,15 @@  synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
   if (trivial_p)
     *trivial_p = expected_trivial;
 
-#ifndef ENABLE_CHECKING
   /* The TYPE_HAS_COMPLEX_* flags tell us about constraints from base
      class versions and other properties of the type.  But a subobject
      class can be trivially copyable and yet have overload resolution
      choose a template constructor for initialization, depending on
      rvalueness and cv-quals.  So we can't exit early for copy/move
-     methods in C++0x.  */
+     methods in C++0x.  The same considerations apply in C++98/03, but
+     there the definition of triviality does not consider overload
+     resolution, so a constructor can be trivial even if it would otherwise
+     call a non-trivial constructor.  */
   if (expected_trivial
       && (!copy_arg_p || cxx_dialect < cxx0x))
     {
@@ -1167,7 +1169,6 @@  synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
 	*constexpr_p = synthesized_default_constructor_is_constexpr (ctype);
       return;
     }
-#endif
 
   ++cp_unevaluated_operand;
   ++c_inhibit_evaluation_warnings;
@@ -1300,14 +1301,6 @@  synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
       if (spec_p)
 	*spec_p = merge_exception_specifiers (*spec_p, cleanup_spec);
     }
-
-#ifdef ENABLE_CHECKING
-  /* If we expected this to be trivial but it isn't, then either we're in
-     C++0x mode and this is a copy/move ctor/op= or there's an error.  */
-  gcc_assert (!(trivial_p && expected_trivial && !*trivial_p)
-	      || (copy_arg_p && cxx_dialect >= cxx0x)
-	      || errorcount);
-#endif
 }
 
 /* DECL is a deleted function.  If it's implicitly deleted, explain why and
diff --git a/gcc/testsuite/g++.dg/cpp0x/implicit-trivial1.C b/gcc/testsuite/g++.dg/cpp0x/implicit-trivial1.C
new file mode 100644
index 0000000..64084c1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/implicit-trivial1.C
@@ -0,0 +1,23 @@ 
+// PR c++/46807
+// { dg-options -std=c++0x }
+// In C++98/03, B::B(const B&) is trivial because A::A(const A&) is trivial,
+// even though doing overload resolution would mean calling the template
+// constructor.  In C++0x, we do overload resolution to determine triviality.
+
+struct A
+{
+  A() {}
+private:
+  template <class T> A(T&);	// { dg-error "private" }
+};
+
+struct B			// { dg-error "implicitly deleted|this context" }
+{
+  mutable A a;
+};
+
+int main()
+{
+  B b;
+  B b2(b);			// { dg-error "deleted" }
+}
diff --git a/gcc/testsuite/g++.dg/inherit/implicit-trivial1.C b/gcc/testsuite/g++.dg/inherit/implicit-trivial1.C
new file mode 100644
index 0000000..e63bd34
--- /dev/null
+++ b/gcc/testsuite/g++.dg/inherit/implicit-trivial1.C
@@ -0,0 +1,23 @@ 
+// PR c++/46807
+// { dg-options -std=c++98 }
+// In C++98/03, B::B(const B&) is trivial because A::A(const A&) is trivial,
+// even though doing overload resolution would mean calling the template
+// constructor.  In C++0x, we do overload resolution to determine triviality.
+
+struct A
+{
+  A() {}
+private:
+  template <class T> A(T&);
+};
+
+struct B
+{
+  mutable A a;
+};
+
+int main()
+{
+  B b;
+  B b2(b);
+}