OSDN Git Service

Implement noexcept operator (5.3.7)
authorjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 4 Jun 2010 21:21:13 +0000 (21:21 +0000)
committerjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 4 Jun 2010 21:21:13 +0000 (21:21 +0000)
* 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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@160297 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/c-common.c
gcc/c-common.h
gcc/cp/ChangeLog
gcc/cp/cp-tree.def
gcc/cp/cp-tree.h
gcc/cp/except.c
gcc/cp/parser.c
gcc/cp/pt.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/noexcept01.C [new file with mode: 0644]

index 21fe05a..7d65c74 100644 (file)
@@ -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
index 97d6034..1c51118 100644 (file)
@@ -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 },
index f0541e9..289d70c 100644 (file)
@@ -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,
index 190406e..0c11af7 100644 (file)
@@ -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.
index c71f94c..b77350f 100644 (file)
@@ -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
index 89a3b7c..e48e469 100644 (file)
@@ -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);
index 6f7f70a..76731f4 100644 (file)
@@ -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;
+}
index 05d713c..32e86e9 100644 (file)
@@ -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;
        }
index dcb455b..0d58035 100644 (file)
@@ -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
index 7f8d144..3eb8e2d 100644 (file)
@@ -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 (file)
index 0000000..e3341d8
--- /dev/null
@@ -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()));