Hi,
this is a rather simple PR about us not rejecting rvalue reference catch
parameters. When I looked into it I noticed that we also aren't
explicitly handling abstract types (which now in C++11 are explicitly
mentioned in [except.handle]): eventually we rejected those but with a
quite poor diagnostic. In fact handling the latter too allows to share
most of the checking code with that on throw expressions, like in the
below is_admissible_throw_operand_or_catch_parameter.
Booted and tested x86_64-linux. Ok?
Thanks,
Paolo.
///////////////////////////
/cp
2012-05-17 Paolo Carlini <paolo.carl...@oracle.com>
PR c++/53371
* except.c (is_admissible_throw_operand): Rename to
is_admissible_throw_operand_or_catch_parameter and handle
catch parameter too.
(expand_start_catch_block): Use it.
(build_throw): Adjust.
/testsuite
2012-05-17 Paolo Carlini <paolo.carl...@oracle.com>
PR c++/53371
* g++.dg/cpp0x/catch1.C: New.
Index: testsuite/g++.dg/cpp0x/catch1.C
===================================================================
--- testsuite/g++.dg/cpp0x/catch1.C (revision 0)
+++ testsuite/g++.dg/cpp0x/catch1.C (revision 0)
@@ -0,0 +1,16 @@
+// PR c++/53371
+// { dg-do compile { target c++11 } }
+
+struct Abs
+{
+ virtual void a() = 0;
+};
+
+void foo()
+{
+ try {
+ } catch (Abs) { } // { dg-error "abstract class type" }
+
+ try {
+ } catch (int&&) { } // { dg-error "rvalue reference type" }
+}
Index: cp/except.c
===================================================================
--- cp/except.c (revision 187624)
+++ cp/except.c (working copy)
@@ -46,7 +46,7 @@ static void initialize_handler_parm (tree, tree);
static tree do_allocate_exception (tree);
static tree wrap_cleanups_r (tree *, int *, void *);
static int complete_ptr_ref_or_void_ptr_p (tree, tree);
-static bool is_admissible_throw_operand (tree);
+static bool is_admissible_throw_operand_or_catch_parameter (tree, bool);
static int can_convert_eh (tree, tree);
/* Sets up all the global eh stuff that needs to be initialized at the
@@ -485,12 +485,13 @@ expand_start_catch_block (tree decl)
if (! doing_eh ())
return NULL_TREE;
- /* Make sure this declaration is reasonable. */
- if (decl && !complete_ptr_ref_or_void_ptr_p (TREE_TYPE (decl), NULL_TREE))
- decl = error_mark_node;
+ if (decl)
+ {
+ if (!is_admissible_throw_operand_or_catch_parameter (decl, false))
+ decl = error_mark_node;
- if (decl)
- type = prepare_eh_type (TREE_TYPE (decl));
+ type = prepare_eh_type (TREE_TYPE (decl));
+ }
else
type = NULL_TREE;
@@ -720,7 +721,7 @@ build_throw (tree exp)
if (exp != NULL_TREE)
{
- if (!is_admissible_throw_operand (exp))
+ if (!is_admissible_throw_operand_or_catch_parameter (exp, true))
return error_mark_node;
}
@@ -944,15 +945,22 @@ complete_ptr_ref_or_void_ptr_p (tree type, tree fr
return 1;
}
-/* Return truth-value if EXPRESSION is admissible in throw-expression,
- i.e. if it is not of incomplete type or a pointer/reference to such
- a type or of an abstract class type. */
+/* If IS_THROW is true return truth-value if T is an expression admissible
+ in throw-expression, i.e. if it is not of incomplete type or a pointer/
+ reference to such a type or of an abstract class type.
+ If IS_THROW is false, likewise for a catch parameter, same requirements
+ for its type plus rvalue reference type is also not admissible. */
static bool
-is_admissible_throw_operand (tree expr)
+is_admissible_throw_operand_or_catch_parameter (tree t, bool is_throw)
{
- tree type = TREE_TYPE (expr);
+ tree expr = is_throw ? t : NULL_TREE;
+ tree type = TREE_TYPE (t);
+ /* C++11 [except.handle] The exception-declaration shall not denote
+ an incomplete type, an abstract class type, or an rvalue reference
+ type. */
+
/* 15.1/4 [...] The type of the throw-expression shall not be an
incomplete type, or a pointer or a reference to an incomplete
type, other than void*, const void*, volatile void*, or
@@ -968,10 +976,22 @@ static bool
conversion. */
else if (CLASS_TYPE_P (type) && CLASSTYPE_PURE_VIRTUALS (type))
{
- error ("expression %qE of abstract class type %qT cannot "
- "be used in throw-expression", expr, type);
+ if (is_throw)
+ error ("expression %qE of abstract class type %qT cannot "
+ "be used in throw-expression", expr, type);
+ else
+ error ("cannot declare catch parameter to be of abstract "
+ "class type %qT", type);
return false;
}
+ else if (!is_throw
+ && TREE_CODE (type) == REFERENCE_TYPE
+ && TYPE_REF_IS_RVALUE (type))
+ {
+ error ("cannot declare catch parameter to be of rvalue "
+ "reference type %qT", type);
+ return false;
+ }
return true;
}