diff mbox

C++0x PATCH to comparison of noexcept specifications

Message ID 4C203B92.8060401@redhat.com
State New
Headers show

Commit Message

Jason Merrill June 22, 2010, 4:26 a.m. UTC
While working on implicit move constructors, I've been running the 
testsuite with -std=gnu++0x, which turned up a bug whereby overriding a 
base method which can throw any exception with a derived method which is 
noexcept was giving an error about a looser exception spec.  Fixed thus.

Tested x86_64-pc-linux-gnu, applied to trunk.
diff mbox

Patch

commit cc07b6735584fe5ee4f692c05d7a0a6abe1a4dbd
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Jun 21 22:04:14 2010 -0400

    	* typeck.c (comp_except_specs): Fix ce_derived with noexcept.

diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index beef388..4383ef5 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -993,35 +993,37 @@  comp_except_specs (const_tree t1, const_tree t2, int exact)
   const_tree probe;
   const_tree base;
   int  length = 0;
-  const_tree noexcept_spec = NULL_TREE;
-  const_tree other_spec;
 
   if (t1 == t2)
     return true;
 
-  /* First test noexcept compatibility.  */
-  if (t1 && TREE_PURPOSE (t1))
-    noexcept_spec = t1, other_spec = t2;
-  else if (t2 && TREE_PURPOSE (t2))
-    noexcept_spec = t2, other_spec = t1;
-  if (noexcept_spec)
-    {
-      tree p = TREE_PURPOSE (noexcept_spec);
-      /* Two noexcept-specs are equivalent iff their exprs are.  */
-      if (other_spec && TREE_PURPOSE (other_spec))
-	return cp_tree_equal (p, TREE_PURPOSE (other_spec));
-      /* noexcept(true) is compatible with throw().  */
-      else if (exact < ce_exact && p == boolean_true_node)
-	return nothrow_spec_p (other_spec);
-      /* noexcept(false) is compatible with any throwing
-	 dynamic-exception-spec.  */
-      else if (exact < ce_exact && p == boolean_false_node)
-	return !nothrow_spec_p (other_spec);
-      /* A dependent noexcept-spec is not compatible with any
-	 dynamic-exception-spec.  */
-      else
-	return false;
-    }
+  /* First handle noexcept.  */
+  if (exact < ce_exact)
+    {
+      /* noexcept(false) is compatible with any throwing dynamic-exc-spec
+	 and stricter than any spec.  */
+      if (t1 == noexcept_false_spec)
+	return !nothrow_spec_p (t2) || exact == ce_derived;
+      /* Even a derived noexcept(false) is compatible with a throwing
+	 dynamic spec.  */
+      if (t2 == noexcept_false_spec)
+	return !nothrow_spec_p (t1);
+
+      /* Otherwise, if we aren't looking for an exact match, noexcept is
+	 equivalent to throw().  */
+      if (t1 == noexcept_true_spec)
+	t1 = empty_except_spec;
+      if (t2 == noexcept_true_spec)
+	t2 = empty_except_spec;
+    }
+
+  /* If any noexcept is left, it is only comparable to itself;
+     either we're looking for an exact match or we're redeclaring a
+     template with dependent noexcept.  */
+  if ((t1 && TREE_PURPOSE (t1))
+      || (t2 && TREE_PURPOSE (t2)))
+    return (t1 && t2
+	    && cp_tree_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2)));
 
   if (t1 == NULL_TREE)			   /* T1 is ...  */
     return t2 == NULL_TREE || exact == ce_derived;
diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept08.C b/gcc/testsuite/g++.dg/cpp0x/noexcept08.C
new file mode 100644
index 0000000..c450332
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/noexcept08.C
@@ -0,0 +1,56 @@ 
+// { dg-options "-std=c++0x" }
+// { dg-prune-output "overriding" }
+
+struct A
+{
+  virtual void f();
+  virtual void g() throw();
+  virtual void h() noexcept;
+  virtual void i() noexcept(false);
+  virtual void j() throw(int);
+};
+
+struct B: A
+{
+  void f() noexcept;
+  void g() noexcept;
+  void h() noexcept;
+  void i() noexcept;
+  void j() noexcept;
+};
+
+struct C: A
+{
+  void f() throw();
+  void g() throw();
+  void h() throw();
+  void i() throw();
+  void j() throw();
+};
+
+struct D: A
+{
+  void f() noexcept(false);
+  void g() noexcept(false);	// { dg-error "looser" }
+  void h() noexcept(false);	// { dg-error "looser" }
+  void i() noexcept(false);
+  void j() noexcept(false);	// compatible; treated as throw(int)
+};
+
+struct E: A
+{
+  void f() throw(int);
+  void g() throw(int);		// { dg-error "looser" }
+  void h() throw(int);		// { dg-error "looser" }
+  void i() throw(int);
+  void j() throw(int);
+};
+
+struct F: A
+{
+  void f();
+  void g();			// { dg-error "looser" }
+  void h();			// { dg-error "looser" }
+  void i();
+  void j();			// { dg-error "looser" }
+};