Commit 0a766368 by Jason Merrill Committed by Jason Merrill

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
parent d8a0d13e
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
......
......@@ -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 },
......
......@@ -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,
......
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.
......
......@@ -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
......
......@@ -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);
......
......@@ -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;
}
......@@ -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;
}
......
......@@ -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
......
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
......
// 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()));
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment