diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index c701767f0eb..6cbd01ef244 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,14 @@ +2002-09-05 Jason Merrill + + * typeck2.c (add_exception_specifier): Only pedwarn for an + incomplete type. + (require_complete_eh_spec_types): New fn. + (cxx_incomplete_type_diagnostic): Also support pedwarning. + * typeck.c (complete_type_or_diagnostic): Likewise. + * call.c (build_call): Call require_complete_eh_spec_types. + * rtti.c (get_pseudo_ti_desc): Give an error rather than aborting + on an incomplete type. + 2002-09-04 Jakub Jelinek * decl.c (start_cleanup_fn): Clear interface_only before diff --git a/gcc/cp/call.c b/gcc/cp/call.c index cbd7faf31a9..36819449bc0 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -356,6 +356,7 @@ build_call (function, parms) tree tmp; tree decl; tree result_type; + tree fntype; function = build_addr_func (function); @@ -365,7 +366,8 @@ build_call (function, parms) return error_mark_node; } - result_type = TREE_TYPE (TREE_TYPE (TREE_TYPE (function))); + fntype = TREE_TYPE (TREE_TYPE (function)); + result_type = TREE_TYPE (fntype); if (TREE_CODE (function) == ADDR_EXPR && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL) @@ -383,6 +385,7 @@ build_call (function, parms) if (decl && TREE_DEPRECATED (decl)) warn_deprecated_use (decl); + require_complete_eh_spec_types (fntype, decl); if (decl && DECL_CONSTRUCTOR_P (decl)) is_constructor = 1; diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c index 0584d60785c..3f671fc30f4 100644 --- a/gcc/cp/rtti.c +++ b/gcc/cp/rtti.c @@ -1198,7 +1198,8 @@ get_pseudo_ti_desc (type) return ptm_desc_type_node; else if (!COMPLETE_TYPE_P (type)) { - my_friendly_assert (at_eof, 20020609); + if (!at_eof) + cxx_incomplete_type_error (NULL_TREE, type); return class_desc_type_node; } else if (!CLASSTYPE_N_BASECLASSES (type)) diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 8535cde4ae7..80da1ed0caa 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -155,16 +155,16 @@ complete_type (type) return type; } -/* Like complete_type, but issue an error if the TYPE cannot be - completed. VALUE is used for informative diagnostics. WARN_ONLY - will cause a warning message to be printed, instead of an error. +/* Like complete_type, but issue an error if the TYPE cannot be completed. + VALUE is used for informative diagnostics. DIAG_TYPE indicates the type + of diagnostic: 0 for an error, 1 for a warning, 2 for a pedwarn. Returns NULL_TREE if the type cannot be made complete. */ tree -complete_type_or_diagnostic (type, value, warn_only) +complete_type_or_diagnostic (type, value, diag_type) tree type; tree value; - int warn_only; + int diag_type; { type = complete_type (type); if (type == error_mark_node) @@ -172,7 +172,7 @@ complete_type_or_diagnostic (type, value, warn_only) return NULL_TREE; else if (!COMPLETE_TYPE_P (type)) { - cxx_incomplete_type_diagnostic (value, type, warn_only); + cxx_incomplete_type_diagnostic (value, type, diag_type); return NULL_TREE; } else diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index e4d7e3eb0a2..67d880905dd 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -182,24 +182,30 @@ abstract_virtuals_error (decl, type) /* Print an error message for invalid use of an incomplete type. VALUE is the expression that was used (or 0 if that isn't known) - and TYPE is the type that was invalid. If WARN_ONLY is nonzero, a - warning is printed, otherwise an error is printed. */ + and TYPE is the type that was invalid. DIAG_TYPE indicates the + type of diagnostic: 0 for an error, 1 for a warning, 2 for a + pedwarn. */ void -cxx_incomplete_type_diagnostic (value, type, warn_only) +cxx_incomplete_type_diagnostic (value, type, diag_type) tree value; tree type; - int warn_only; + int diag_type; { int decl = 0; void (*p_msg) PARAMS ((const char *, ...)); void (*p_msg_at) PARAMS ((const char *, ...)); - if (warn_only) + if (diag_type == 1) { p_msg = warning; p_msg_at = cp_warning_at; } + else if (diag_type == 2) + { + p_msg = pedwarn; + p_msg_at = cp_pedwarn_at; + } else { p_msg = error; @@ -1345,6 +1351,7 @@ add_exception_specifier (list, spec, complain) int ok; tree core = spec; int is_ptr; + int diag_type = -1; /* none */ if (spec == error_mark_node) return list; @@ -1366,7 +1373,15 @@ add_exception_specifier (list, spec, complain) else if (processing_template_decl) ok = 1; else - ok = COMPLETE_TYPE_P (complete_type (core)); + { + ok = 1; + /* 15.4/1 says that types in an exception specifier must be complete, + but it seems more reasonable to only require this on definitions + and calls. So just give a pedwarn at this point; we will give an + error later if we hit one of those two cases. */ + if (!COMPLETE_TYPE_P (complete_type (core))) + diag_type = 2; /* pedwarn */ + } if (ok) { @@ -1378,8 +1393,12 @@ add_exception_specifier (list, spec, complain) if (!probe) list = tree_cons (NULL_TREE, spec, list); } - else if (complain) - cxx_incomplete_type_error (NULL_TREE, core); + else + diag_type = 0; /* error */ + + if (diag_type >= 0 && complain) + cxx_incomplete_type_diagnostic (NULL_TREE, core, diag_type); + return list; } @@ -1418,3 +1437,34 @@ merge_exception_specifiers (list, add) } return list; } + +/* Subroutine of build_call. Ensure that each of the types in the + exception specification is complete. Technically, 15.4/1 says that + they need to be complete when we see a declaration of the function, + but we should be able to get away with only requiring this when the + function is defined or called. See also add_exception_specifier. */ + +void +require_complete_eh_spec_types (fntype, decl) + tree fntype, decl; +{ + tree raises; + /* Don't complain about calls to op new. */ + if (decl && DECL_ARTIFICIAL (decl)) + return; + for (raises = TYPE_RAISES_EXCEPTIONS (fntype); raises; + raises = TREE_CHAIN (raises)) + { + tree type = TREE_VALUE (raises); + if (type && !COMPLETE_TYPE_P (type)) + { + if (decl) + error + ("call to function `%D' which throws incomplete type `%#T'", + decl, type); + else + error ("call to function which throws incomplete type `%#T'", + decl); + } + } +} diff --git a/gcc/testsuite/g++.dg/eh/spec5.C b/gcc/testsuite/g++.dg/eh/spec5.C new file mode 100644 index 00000000000..be8f327c0b7 --- /dev/null +++ b/gcc/testsuite/g++.dg/eh/spec5.C @@ -0,0 +1,22 @@ +// Test for extension to allow incomplete types in an +// exception-specification for a declaration. + +// { dg-do run } +// { dg-options "-fpermissive -w" } + +struct A; + +struct B +{ + void f () throw (A); +}; + +struct A {}; + +void B::f () throw (A) {} + +int main () +{ + B b; + b.f(); +} diff --git a/gcc/testsuite/g++.dg/eh/spec6.C b/gcc/testsuite/g++.dg/eh/spec6.C new file mode 100644 index 00000000000..eb1177b07f5 --- /dev/null +++ b/gcc/testsuite/g++.dg/eh/spec6.C @@ -0,0 +1,19 @@ +// Test that we don't allow incomplete types in an exception-specification +// for a definition, or at a call site. + +// { dg-options "-fpermissive -w" } + +struct A; // { dg-error "" } + +struct B +{ + void f () throw (A); +}; + +void B::f () throw (A) {} // { dg-error "A" } + +int main () +{ + B b; + b.f(); // { dg-error "A" } +}