aboutsummaryrefslogtreecommitdiff
path: root/gcc
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
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')
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/c-common.c1
-rw-r--r--gcc/c-common.h2
-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
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/noexcept01.C75
11 files changed, 220 insertions, 1 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 21fe05a..7d65c74 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2010-06-03 Jason Merrill <jason@redhat.com>
+
+ Implement noexcept operator (5.3.7)
+ * c-common.c (c_common_reswords): Add noexcept.
+ * c-common.h (enum rid): Add RID_NOEXCEPT.
+
2010-06-04 Joseph Myers <joseph@codesourcery.com>
* config/darwin-driver.c (darwin_default_min_version): Use
diff --git a/gcc/c-common.c b/gcc/c-common.c
index 97d6034..1c51118 100644
--- a/gcc/c-common.c
+++ b/gcc/c-common.c
@@ -661,6 +661,7 @@ const struct c_common_resword c_common_reswords[] =
{ "mutable", RID_MUTABLE, D_CXXONLY | D_CXXWARN },
{ "namespace", RID_NAMESPACE, D_CXXONLY | D_CXXWARN },
{ "new", RID_NEW, D_CXXONLY | D_CXXWARN },
+ { "noexcept", RID_NOEXCEPT, D_CXXONLY | D_CXX0X | D_CXXWARN },
{ "nullptr", RID_NULLPTR, D_CXXONLY | D_CXX0X | D_CXXWARN },
{ "operator", RID_OPERATOR, D_CXXONLY | D_CXXWARN },
{ "private", RID_PRIVATE, D_CXX_OBJC | D_CXXWARN },
diff --git a/gcc/c-common.h b/gcc/c-common.h
index f0541e9..289d70c 100644
--- a/gcc/c-common.h
+++ b/gcc/c-common.h
@@ -125,7 +125,7 @@ enum rid
RID_IS_UNION,
/* C++0x */
- RID_CONSTEXPR, RID_DECLTYPE, RID_NULLPTR, RID_STATIC_ASSERT,
+ RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
/* Objective-C */
RID_AT_ENCODE, RID_AT_END,
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
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 7f8d144..3eb8e2d 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2010-06-04 Jason Merrill <jason@redhat.com>
+
+ * g++.dg/cpp0x/noexcept01.C: New.
+
2010-06-04 Jakub Jelinek <jakub@redhat.com>
PR c++/44412
diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept01.C b/gcc/testsuite/g++.dg/cpp0x/noexcept01.C
new file mode 100644
index 0000000..e3341d8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/noexcept01.C
@@ -0,0 +1,75 @@
+// Test for noexcept-expression
+// { dg-options "-std=c++0x -O2" }
+
+#include <typeinfo>
+
+#define SA(X) static_assert(X, #X)
+
+void f();
+void g() throw();
+SA(noexcept(g()));
+SA(!noexcept(f()));
+SA(!noexcept(throw 1));
+SA(noexcept(42));
+
+struct A
+{
+ virtual ~A();
+};
+
+struct B: public A
+{
+ virtual ~B();
+};
+
+A* ap;
+
+struct C { };
+C* cp;
+
+SA (noexcept (dynamic_cast<B*>(ap)));
+SA (!noexcept (dynamic_cast<B&>(*ap)));
+SA (!noexcept (typeid (*ap)));
+SA (noexcept (typeid (*cp)));
+
+SA (!noexcept (true ? 1 : throw 1));
+SA (!noexcept (true || true ? 1 : throw 1));
+
+SA (noexcept (C()));
+
+struct D
+{
+ D() throw();
+};
+
+SA (noexcept (D()));
+
+struct E
+{
+ E() throw();
+ ~E();
+};
+
+SA (!noexcept (E()));
+
+struct F
+{
+ virtual void f();
+};
+
+SA (noexcept (F()));
+
+template <class T, bool b>
+void tf()
+{
+ SA (noexcept (T()) == b);
+}
+
+template void tf<int,true>();
+template void tf<E, false>();
+
+// Make sure that noexcept uses the declared exception-specification, not
+// any knowledge we might have about whether or not the function really
+// throws.
+void h() { }
+SA(!noexcept(h()));