aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2010-06-04 17:21:13 -0400
committerJason Merrill <jason@gcc.gnu.org>2010-06-04 17:21:13 -0400
commit0a766368bd6e51459bfd334086cc04af48f91f08 (patch)
treed5300c246ce3ea5275af264865375de418f7963e /gcc/cp
parentd8a0d13e4fad752b3c3d9ff3f97b03407bf8c726 (diff)
downloadgcc-0a766368bd6e51459bfd334086cc04af48f91f08.zip
gcc-0a766368bd6e51459bfd334086cc04af48f91f08.tar.gz
gcc-0a766368bd6e51459bfd334086cc04af48f91f08.tar.bz2
Implement noexcept operator (5.3.7)
Implement noexcept operator (5.3.7) * c-common.c (c_common_reswords): Add noexcept. * c-common.h (enum rid): Add RID_NOEXCEPT. cp/ * cp-tree.def (NOEXCEPT_EXPR): New. * except.c (check_noexcept_r, finish_noexcept_expr): New. * cp-tree.h: Declare finish_noexcept_expr. * parser.c (cp_parser_unary_expression): Parse noexcept-expression. * pt.c (tsubst_copy_and_build): And tsubst it. (type_dependent_expression_p): Handle it. (value_dependent_expression_p): Handle it. From-SVN: r160297
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/ChangeLog9
-rw-r--r--gcc/cp/cp-tree.def1
-rw-r--r--gcc/cp/cp-tree.h1
-rw-r--r--gcc/cp/except.c64
-rw-r--r--gcc/cp/parser.c45
-rw-r--r--gcc/cp/pt.c13
6 files changed, 133 insertions, 0 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 190406e..0c11af7 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,14 @@
2010-06-04 Jason Merrill <jason@redhat.com>
+ Implement noexcept operator (5.3.7)
+ * cp-tree.def (NOEXCEPT_EXPR): New.
+ * except.c (check_noexcept_r, finish_noexcept_expr): New.
+ * cp-tree.h: Declare finish_noexcept_expr.
+ * parser.c (cp_parser_unary_expression): Parse noexcept-expression.
+ * pt.c (tsubst_copy_and_build): And tsubst it.
+ (type_dependent_expression_p): Handle it.
+ (value_dependent_expression_p): Handle it.
+
* call.c (build_conditional_expr): Never fold in unevaluated context.
* tree.c (build_aggr_init_expr): Propagate TREE_NOTHROW.
* semantics.c (simplify_aggr_init_expr): Likewise.
diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
index c71f94c..b77350f 100644
--- a/gcc/cp/cp-tree.def
+++ b/gcc/cp/cp-tree.def
@@ -247,6 +247,7 @@ DEFTREECODE (STATIC_CAST_EXPR, "static_cast_expr", tcc_unary, 1)
DEFTREECODE (DYNAMIC_CAST_EXPR, "dynamic_cast_expr", tcc_unary, 1)
DEFTREECODE (DOTSTAR_EXPR, "dotstar_expr", tcc_expression, 2)
DEFTREECODE (TYPEID_EXPR, "typeid_expr", tcc_expression, 1)
+DEFTREECODE (NOEXCEPT_EXPR, "noexcept_expr", tcc_unary, 1)
/* A placeholder for an expression that is not type-dependent, but
does occur in a template. When an expression that is not
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 89a3b7c..e48e469 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4820,6 +4820,7 @@ extern tree build_exc_ptr (void);
extern tree build_throw (tree);
extern int nothrow_libfn_p (const_tree);
extern void check_handlers (tree);
+extern tree finish_noexcept_expr (tree);
extern void choose_personality_routine (enum languages);
extern tree eh_type_info (tree);
extern tree begin_eh_spec_block (void);
diff --git a/gcc/cp/except.c b/gcc/cp/except.c
index 6f7f70a..76731f4 100644
--- a/gcc/cp/except.c
+++ b/gcc/cp/except.c
@@ -998,3 +998,67 @@ check_handlers (tree handlers)
check_handlers_1 (handler, i);
}
}
+
+/* walk_tree helper for finish_noexcept_expr. Returns non-null if the
+ expression *TP causes the noexcept operator to evaluate to false.
+
+ 5.3.7 [expr.noexcept]: The result of the noexcept operator is false if
+ in a potentially-evaluated context the expression would contain
+ * a potentially evaluated call to a function, member function,
+ function pointer, or member function pointer that does not have a
+ non-throwing exception-specification (15.4),
+ * a potentially evaluated throw-expression (15.1),
+ * a potentially evaluated dynamic_cast expression dynamic_cast<T>(v),
+ where T is a reference type, that requires a run-time check (5.2.7), or
+ * a potentially evaluated typeid expression (5.2.8) applied to a glvalue
+ expression whose type is a polymorphic class type (10.3). */
+
+static tree
+check_noexcept_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
+ void *data ATTRIBUTE_UNUSED)
+{
+ tree t = *tp;
+ enum tree_code code = TREE_CODE (t);
+ if (code == CALL_EXPR
+ || code == AGGR_INIT_EXPR)
+ {
+ /* We can only use the exception specification of the called function
+ for determining the value of a noexcept expression; we can't use
+ TREE_NOTHROW, as it might have a different value in another
+ translation unit, creating ODR problems.
+
+ We could use TREE_NOTHROW (t) for !TREE_PUBLIC fns, though... */
+ tree fn = (code == AGGR_INIT_EXPR
+ ? AGGR_INIT_EXPR_FN (t) : CALL_EXPR_FN (t));
+ if (TREE_CODE (fn) == ADDR_EXPR)
+ {
+ /* We do use TREE_NOTHROW for ABI internals like __dynamic_cast,
+ and for C library functions known not to throw. */
+ tree fn2 = TREE_OPERAND (fn, 0);
+ if (TREE_CODE (fn2) == FUNCTION_DECL
+ && DECL_EXTERN_C_P (fn2)
+ && (DECL_ARTIFICIAL (fn2)
+ || nothrow_libfn_p (fn2)))
+ return TREE_NOTHROW (fn2) ? NULL_TREE : t;
+ }
+ fn = TREE_TYPE (TREE_TYPE (fn));
+ if (!TYPE_NOTHROW_P (fn))
+ return t;
+ }
+
+ return NULL_TREE;
+}
+
+/* Evaluate noexcept ( EXPR ). */
+
+tree
+finish_noexcept_expr (tree expr)
+{
+ if (processing_template_decl)
+ return build_min (NOEXCEPT_EXPR, boolean_type_node, expr);
+
+ if (cp_walk_tree_without_duplicates (&expr, check_noexcept_r, 0))
+ return boolean_false_node;
+ else
+ return boolean_true_node;
+}
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 05d713c..32e86e9 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -5841,6 +5841,51 @@ cp_parser_unary_expression (cp_parser *parser, bool address_p, bool cast_p,
}
break;
+ case RID_NOEXCEPT:
+ {
+ tree expr;
+ const char *saved_message;
+ bool saved_integral_constant_expression_p;
+ bool saved_non_integral_constant_expression_p;
+ bool saved_greater_than_is_operator_p;
+
+ cp_lexer_consume_token (parser->lexer);
+ cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN);
+
+ saved_message = parser->type_definition_forbidden_message;
+ parser->type_definition_forbidden_message
+ = G_("types may not be defined in %<noexcept%> expressions");
+
+ saved_integral_constant_expression_p
+ = parser->integral_constant_expression_p;
+ saved_non_integral_constant_expression_p
+ = parser->non_integral_constant_expression_p;
+ parser->integral_constant_expression_p = false;
+
+ saved_greater_than_is_operator_p
+ = parser->greater_than_is_operator_p;
+ parser->greater_than_is_operator_p = true;
+
+ ++cp_unevaluated_operand;
+ ++c_inhibit_evaluation_warnings;
+ expr = cp_parser_expression (parser, false, NULL);
+ --c_inhibit_evaluation_warnings;
+ --cp_unevaluated_operand;
+
+ parser->greater_than_is_operator_p
+ = saved_greater_than_is_operator_p;
+
+ parser->integral_constant_expression_p
+ = saved_integral_constant_expression_p;
+ parser->non_integral_constant_expression_p
+ = saved_non_integral_constant_expression_p;
+
+ parser->type_definition_forbidden_message = saved_message;
+
+ cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
+ return finish_noexcept_expr (expr);
+ }
+
default:
break;
}
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index dcb455b..0d58035 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -12245,6 +12245,17 @@ tsubst_copy_and_build (tree t,
return cxx_sizeof_or_alignof_expr (op1, TREE_CODE (t),
complain & tf_error);
+ case NOEXCEPT_EXPR:
+ op1 = TREE_OPERAND (t, 0);
+ ++cp_unevaluated_operand;
+ ++c_inhibit_evaluation_warnings;
+ op1 = tsubst_copy_and_build (op1, args, complain, in_decl,
+ /*function_p=*/false,
+ /*integral_constant_expression_p=*/false);
+ --cp_unevaluated_operand;
+ --c_inhibit_evaluation_warnings;
+ return finish_noexcept_expr (op1);
+
case MODOP_EXPR:
{
tree r = build_x_modify_expr
@@ -17577,6 +17588,7 @@ value_dependent_expression_p (tree expression)
return true;
else if (TYPE_P (expression))
return dependent_type_p (expression);
+ case NOEXCEPT_EXPR:
return type_dependent_expression_p (expression);
case SCOPE_REF:
@@ -17680,6 +17692,7 @@ type_dependent_expression_p (tree expression)
if (TREE_CODE (expression) == PSEUDO_DTOR_EXPR
|| TREE_CODE (expression) == SIZEOF_EXPR
|| TREE_CODE (expression) == ALIGNOF_EXPR
+ || TREE_CODE (expression) == NOEXCEPT_EXPR
|| TREE_CODE (expression) == TRAIT_EXPR
|| TREE_CODE (expression) == TYPEID_EXPR
|| TREE_CODE (expression) == DELETE_EXPR