aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2019-10-23 20:41:26 +0000
committerJason Merrill <jason@redhat.com>2019-10-23 20:41:26 +0000
commit421e9b156df0b300c0446d9818ce6d59e31b1ae2 (patch)
tree18bcab37dfecdae810feb52e18f4461f970f4fbe
parent2a68eea06ea1f566ba3ab45ec20cd304f0982aaa (diff)
Implement P1286R2, Contra CWG1778
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. * 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. git-svn-id: https://gcc.gnu.org/svn/gcc/trunk@277351 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/cp/ChangeLog11
-rw-r--r--gcc/cp/method.c69
-rw-r--r--gcc/cp/parser.c14
-rw-r--r--gcc/cp/parser.h4
-rw-r--r--gcc/testsuite/g++.dg/DRs/dr1778.C7
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/defaulted23.C4
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/defaulted43.C10
7 files changed, 32 insertions, 87 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index d1518123b24..f587f15ddd7 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,14 @@
+2019-10-23 Jason Merrill <jason@redhat.com>
+
+ Implement P1286R2, Contra CWG1778
+ * 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.
+
2019-10-23 Jakub Jelinek <jakub@redhat.com>
* constexpr.c (cxx_eval_constant_expression) <case CLEANUP_STMT>:
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 c597adb38f1..3857fe47d67 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/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/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;