c++: Fix noexcept with unevaluated operand [PR101087]
authorMarek Polacek <polacek@redhat.com>
Thu, 8 Jul 2021 00:02:18 +0000 (20:02 -0400)
committerMarek Polacek <polacek@redhat.com>
Thu, 8 Jul 2021 21:38:49 +0000 (17:38 -0400)
It sounds plausible that this assert

  int f();
  static_assert(noexcept(sizeof(f())));

should pass: sizeof produces a std::size_t and its operand is not
evaluated, so it can't throw.  noexcept should only evaluate to
false for potentially evaluated operands.  Therefore I think that
check_noexcept_r shouldn't walk into operands of sizeof/decltype/
alignof/typeof.

PR c++/101087

gcc/cp/ChangeLog:

* cp-tree.h (unevaluated_p): New.
* except.c (check_noexcept_r): Use it.  Don't walk into
unevaluated operands.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/noexcept70.C: New test.

gcc/cp/cp-tree.h
gcc/cp/except.c
gcc/testsuite/g++.dg/cpp0x/noexcept70.C [new file with mode: 0644]

index b450157..d4810c0 100644 (file)
@@ -8465,6 +8465,19 @@ is_constrained_auto (const_tree t)
   return is_auto (t) && PLACEHOLDER_TYPE_CONSTRAINTS_INFO (t);
 }
 
+/* True if CODE, a tree code, denotes a tree whose operand is not evaluated
+   as per [expr.context], i.e., an operand to sizeof, typeof, decltype, or
+   alignof.  */
+
+inline bool
+unevaluated_p (tree_code code)
+{
+  return (code == DECLTYPE_TYPE
+         || code == ALIGNOF_EXPR
+         || code == SIZEOF_EXPR
+         || code == NOEXCEPT_EXPR);
+}
+
 /* RAII class to push/pop the access scope for T.  */
 
 struct push_access_scope_guard
index a8cea53..a8acbc4 100644 (file)
@@ -1033,12 +1033,15 @@ check_handlers (tree handlers)
      expression whose type is a polymorphic class type (10.3).  */
 
 static tree
-check_noexcept_r (tree *tp, int * /*walk_subtrees*/, void * /*data*/)
+check_noexcept_r (tree *tp, int *walk_subtrees, void *)
 {
   tree t = *tp;
   enum tree_code code = TREE_CODE (t);
-  if ((code == CALL_EXPR && CALL_EXPR_FN (t))
-      || code == AGGR_INIT_EXPR)
+
+  if (unevaluated_p (code))
+    *walk_subtrees = false;
+  else if ((code == CALL_EXPR && CALL_EXPR_FN (t))
+          || 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
diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept70.C b/gcc/testsuite/g++.dg/cpp0x/noexcept70.C
new file mode 100644 (file)
index 0000000..45a6137
--- /dev/null
@@ -0,0 +1,5 @@
+// PR c++/101087
+// { dg-do compile { target c++11 } }
+
+int f();
+static_assert(noexcept(sizeof(f())), "");