diff mbox series

[C++] Implement P1286R2, Contra CWG1778

Message ID 20191023204058.14971-1-jason@redhat.com
State New
Headers show
Series [C++] Implement P1286R2, Contra CWG1778 | expand

Commit Message

Jason Merrill Oct. 23, 2019, 8:40 p.m. UTC
The C++11 requirement that an explicit exception-specification on a
defaulted function match the implicit one was found to be problematic for
std::atomic.  This paper, adopted in February, simply removes that
requirement: if an explicitly defaulted function has a different
exception-specification, that now works just like a user-written function:
either it isn't noexcept when it could be, or it is noexcept and will call
terminate if an exception is thrown.

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

	* method.c (defaulted_late_check): Don't check explicit
	exception-specification on defaulted function.
	(after_nsdmi_defaulted_late_checks): Remove.
	* parser.h (struct cp_unparsed_functions_entry): Remove classes.
	* parser.c (unparsed_classes): Remove.
	(push_unparsed_function_queues, cp_parser_class_specifier_1):
	Adjust.
---
 gcc/cp/parser.h                          |  4 --
 gcc/cp/method.c                          | 69 +++---------------------
 gcc/cp/parser.c                          | 14 +----
 gcc/testsuite/g++.dg/DRs/dr1778.C        |  7 +++
 gcc/testsuite/g++.dg/cpp0x/defaulted23.C |  4 +-
 gcc/testsuite/g++.dg/cpp0x/defaulted43.C | 10 ++--
 6 files changed, 21 insertions(+), 87 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/DRs/dr1778.C


base-commit: e04a052b62e09874b0d61a217a5eb5b6eae5cdc5
diff mbox series

Patch

diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h
index 91b5916622d..200498281b5 100644
--- a/gcc/cp/parser.h
+++ b/gcc/cp/parser.h
@@ -163,10 +163,6 @@  struct GTY(()) cp_unparsed_functions_entry {
      FIELD_DECLs appear in this list in declaration order.  */
   vec<tree, va_gc> *nsdmis;
 
-  /* Nested classes go in this vector, so that we can do some final
-     processing after parsing any NSDMIs.  */
-  vec<tree, va_gc> *classes;
-
   /* Functions with noexcept-specifiers that require post-processing.  */
   vec<tree, va_gc> *noexcepts;
 };
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 73a01147ff9..b613e5df871 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -2204,40 +2204,12 @@  defaulted_late_check (tree fn)
       return;
     }
 
-  /* 8.4.2/2: An explicitly-defaulted function (...) may have an explicit
-     exception-specification only if it is compatible (15.4) with the 
-     exception-specification on the implicit declaration.  If a function
-     is explicitly defaulted on its first declaration, (...) it is
-     implicitly considered to have the same exception-specification as if
-     it had been implicitly declared.  */
-  maybe_instantiate_noexcept (fn);
-  tree fn_spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
-  if (!fn_spec)
-    {
-      if (DECL_DEFAULTED_IN_CLASS_P (fn))
-	TREE_TYPE (fn) = build_exception_variant (TREE_TYPE (fn), eh_spec);
-    }
-  else if (UNEVALUATED_NOEXCEPT_SPEC_P (fn_spec))
-    /* Equivalent to the implicit spec.  */;
-  else if (DECL_DEFAULTED_IN_CLASS_P (fn)
-	   && !CLASSTYPE_TEMPLATE_INSTANTIATION (ctx))
-    /* We can't compare an explicit exception-specification on a
-       constructor defaulted in the class body to the implicit
-       exception-specification until after we've parsed any NSDMI; see
-       after_nsdmi_defaulted_late_checks.  */;
-  else
-    {
-      tree eh_spec = get_defaulted_eh_spec (fn);
-      if (!comp_except_specs (fn_spec, eh_spec, ce_normal))
-	{
-	  if (DECL_DEFAULTED_IN_CLASS_P (fn))
-	    DECL_DELETED_FN (fn) = true;
-	  else
-	    error ("function %q+D defaulted on its redeclaration "
-		   "with an exception-specification that differs from "
-		   "the implicit exception-specification %qX", fn, eh_spec);
-	}
-    }
+  /* If a function is explicitly defaulted on its first declaration without an
+     exception-specification, it is implicitly considered to have the same
+     exception-specification as if it had been implicitly declared.  */
+  if (!TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn))
+      && DECL_DEFAULTED_IN_CLASS_P (fn))
+    TREE_TYPE (fn) = build_exception_variant (TREE_TYPE (fn), eh_spec);
 
   if (DECL_DEFAULTED_IN_CLASS_P (fn)
       && DECL_DECLARED_CONSTEXPR_P (implicit_fn))
@@ -2264,35 +2236,6 @@  defaulted_late_check (tree fn)
     }
 }
 
-/* OK, we've parsed the NSDMI for class T, now we can check any explicit
-   exception-specifications on functions defaulted in the class body.  */
-
-void
-after_nsdmi_defaulted_late_checks (tree t)
-{
-  if (uses_template_parms (t))
-    return;
-  if (t == error_mark_node)
-    return;
-  for (tree fn = TYPE_FIELDS (t); fn; fn = DECL_CHAIN (fn))
-    if (!DECL_ARTIFICIAL (fn)
-	&& DECL_DECLARES_FUNCTION_P (fn)
-	&& DECL_DEFAULTED_IN_CLASS_P (fn))
-      {
-	tree fn_spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
-	if (UNEVALUATED_NOEXCEPT_SPEC_P (fn_spec))
-	  continue;
-
-	tree eh_spec = get_defaulted_eh_spec (fn);
-	if (eh_spec == error_mark_node)
-	  continue;
-
-	if (!comp_except_specs (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)),
-				eh_spec, ce_normal))
-	  DECL_DELETED_FN (fn) = true;
-      }
-}
-
 /* Returns true iff FN can be explicitly defaulted, and gives any
    errors if defaulting FN is ill-formed.  */
 
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 6433f870b2e..60a46af804d 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -2005,16 +2005,13 @@  cp_parser_context_new (cp_parser_context* next)
   parser->unparsed_queues->last ().funs_with_definitions
 #define unparsed_nsdmis \
   parser->unparsed_queues->last ().nsdmis
-#define unparsed_classes \
-  parser->unparsed_queues->last ().classes
 #define unparsed_noexcepts \
   parser->unparsed_queues->last ().noexcepts
 
 static void
 push_unparsed_function_queues (cp_parser *parser)
 {
-  cp_unparsed_functions_entry e = { NULL, make_tree_vector (), NULL, NULL,
-				    NULL };
+  cp_unparsed_functions_entry e = { NULL, make_tree_vector (), NULL, NULL };
   vec_safe_push (parser->unparsed_queues, e);
 }
 
@@ -23754,7 +23751,6 @@  cp_parser_class_specifier_1 (cp_parser* parser)
 	     error recovery (c++/71169, c++/71832).  */
 	  vec_safe_truncate (unparsed_funs_with_default_args, 0);
 	  vec_safe_truncate (unparsed_nsdmis, 0);
-	  vec_safe_truncate (unparsed_classes, 0);
 	  vec_safe_truncate (unparsed_funs_with_definitions, 0);
 	}
 
@@ -23809,12 +23805,6 @@  cp_parser_class_specifier_1 (cp_parser* parser)
       if (pushed_scope)
 	pop_scope (pushed_scope);
 
-      /* Now do some post-NSDMI bookkeeping.  */
-      FOR_EACH_VEC_SAFE_ELT (unparsed_classes, ix, class_type)
-	after_nsdmi_defaulted_late_checks (class_type);
-      vec_safe_truncate (unparsed_classes, 0);
-      after_nsdmi_defaulted_late_checks (type);
-
       /* If there are noexcept-specifiers that have not yet been processed,
 	 take care of them now.  */
       class_type = NULL_TREE;
@@ -23885,8 +23875,6 @@  cp_parser_class_specifier_1 (cp_parser* parser)
 	  cp_parser_late_parsing_for_member (parser, decl);
       vec_safe_truncate (unparsed_funs_with_definitions, 0);
     }
-  else
-    vec_safe_push (unparsed_classes, type);
 
   /* Put back any saved access checks.  */
   pop_deferring_access_checks ();
diff --git a/gcc/testsuite/g++.dg/DRs/dr1778.C b/gcc/testsuite/g++.dg/DRs/dr1778.C
new file mode 100644
index 00000000000..8db937fc0bf
--- /dev/null
+++ b/gcc/testsuite/g++.dg/DRs/dr1778.C
@@ -0,0 +1,7 @@ 
+// P1286R2: Contra CWG1778
+// { dg-do compile { target c++11 } }
+
+struct T { T(); T(T &&) noexcept(false); };
+struct U { T t; U(); U(U &&) noexcept = default; };
+U u1;
+U u2 = static_cast<U&&>(u1);      // OK, calls std::terminate if T::T(T&&) throws
diff --git a/gcc/testsuite/g++.dg/cpp0x/defaulted23.C b/gcc/testsuite/g++.dg/cpp0x/defaulted23.C
index dfbdd2f2ed1..23848633c3c 100644
--- a/gcc/testsuite/g++.dg/cpp0x/defaulted23.C
+++ b/gcc/testsuite/g++.dg/cpp0x/defaulted23.C
@@ -10,10 +10,10 @@  A a;
 
 struct B
 {
-  B() throw (int) = default; // { dg-message "exception-specification" "" { target { ! c++17 } } }
+  B() throw (int) = default;
 };				// { dg-error "dynamic exception specification" "" { target c++17 } .-1 }
 				// { dg-warning "deprecated" "" { target { ! c++17 } } .-2 }
-B b;				// { dg-error "deleted" "" { target { ! c++17 } } }
+B b;
 
 struct C
 {
diff --git a/gcc/testsuite/g++.dg/cpp0x/defaulted43.C b/gcc/testsuite/g++.dg/cpp0x/defaulted43.C
index f2846fe390c..1fe7818ec67 100644
--- a/gcc/testsuite/g++.dg/cpp0x/defaulted43.C
+++ b/gcc/testsuite/g++.dg/cpp0x/defaulted43.C
@@ -17,8 +17,8 @@  struct A
   T t;
 };
 
-A::A() noexcept = default;   // { dg-error "defaulted" }
-A::~A() noexcept = default;  // { dg-error "defaulted" }
+A::A() noexcept = default;
+A::~A() noexcept = default;
 
 struct U
 {
@@ -51,10 +51,10 @@  V v;
 
 struct C
 {
-  C() noexcept = default;	// { dg-message "exception-specification" }
-  ~C() noexcept = default;	// { dg-message "exception-specification" }
+  C() noexcept = default;
+  ~C() noexcept = default;
 
   V v;
 };
 
-C c;				// { dg-error "deleted" }
+C c;