On 3/5/21 5:50 PM, Marek Polacek wrote:
This is an ICE on invalid where we crash because since r269032 we
keep error_mark_node around instead of using noexcept_false_spec
when things go wrong; see the walk_field_subobs hunk.

We crash in deduce_inheriting_ctor which calls synthesized_method_walk
to deduce the exception-specification, but fails to do so in this case,
because the testcase is invalid so get_nsdmi returns error_mark_node for
the member 'c', and per r269032 the error_mark_node propagates back to
deduce_inheriting_ctor which subsequently calls build_exception_variant
whereon we crash.  I think we should return early if the deduction fails
and I decided to call mark_used to get an error right away instead of
hoping that it would get called later.  My worry is that we could forget
that there was an error and think that we just deduced noexcept(false).

And then I noticed that the test still crashes in C++98.  Here again we
failed to deduce the exception-specification in implicitly_declare_fn,
but nothing reported an error between synthesized_method_walk and the
assert.  Well, not much we can do except calling synthesized_method_walk
again, this time in the verbose mode and making sure that we did get an
error.

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

OK.

gcc/cp/ChangeLog:

        PR c++/94751
        * call.c (build_over_call): Maybe call mark_used in case
        deduce_inheriting_ctor fails and return error_mark_node.
        * cp-tree.h (deduce_inheriting_ctor): Adjust declaration.
        * method.c (deduce_inheriting_ctor): Return bool if the deduction
        fails.
        (implicitly_declare_fn): If raises is error_mark_node, call
        synthesized_method_walk with diag being true.

gcc/testsuite/ChangeLog:

        PR c++/94751
        * g++.dg/cpp0x/inh-ctor37.C: New test.
---
  gcc/cp/call.c                           |  9 +++++++--
  gcc/cp/cp-tree.h                        |  2 +-
  gcc/cp/method.c                         | 22 ++++++++++++++++-----
  gcc/testsuite/g++.dg/cpp0x/inh-ctor37.C | 26 +++++++++++++++++++++++++
  4 files changed, 51 insertions(+), 8 deletions(-)
  create mode 100644 gcc/testsuite/g++.dg/cpp0x/inh-ctor37.C

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 123f06b1f2b..fa42165c209 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -8917,8 +8917,13 @@ build_over_call (struct z_candidate *cand, int flags, 
tsubst_flags_t complain)
    /* OK, we're actually calling this inherited constructor; set its 
deletedness
       appropriately.  We can get away with doing this here because calling is
       the only way to refer to a constructor.  */
-  if (DECL_INHERITED_CTOR (fn))
-    deduce_inheriting_ctor (fn);
+  if (DECL_INHERITED_CTOR (fn)
+      && !deduce_inheriting_ctor (fn))
+    {
+      if (complain & tf_error)
+       mark_used (fn);
+      return error_mark_node;
+    }
/* Make =delete work with SFINAE. */
    if (DECL_DELETED_FN (fn))
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 39e2ad83abd..587cf35a271 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6919,7 +6919,7 @@ extern bool is_xible                              (enum 
tree_code, tree, tree);
  extern tree get_defaulted_eh_spec             (tree, tsubst_flags_t = 
tf_warning_or_error);
  extern bool maybe_explain_implicit_delete     (tree);
  extern void explain_implicit_non_constexpr    (tree);
-extern void deduce_inheriting_ctor             (tree);
+extern bool deduce_inheriting_ctor             (tree);
  extern bool decl_remember_implicit_trigger_p  (tree);
  extern void synthesize_method                 (tree);
  extern tree lazily_declare_fn                 (special_function_kind,
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 3fe3bd82a7d..25c1e681b99 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -2789,9 +2789,9 @@ explain_implicit_non_constexpr (tree decl)
/* DECL is an instantiation of an inheriting constructor template. Deduce
     the correct exception-specification and deletedness for this particular
-   specialization.  */
+   specialization.  Return true if the deduction succeeds; false otherwise.  */
-void
+bool
  deduce_inheriting_ctor (tree decl)
  {
    decl = DECL_ORIGIN (decl);
@@ -2804,6 +2804,8 @@ deduce_inheriting_ctor (tree decl)
                           /*diag*/false,
                           &inh,
                           FUNCTION_FIRST_USER_PARMTYPE (decl));
+  if (spec == error_mark_node)
+    return false;
    if (TREE_CODE (inherited_ctor_binfo (decl)) != TREE_BINFO)
      /* Inherited the same constructor from different base subobjects.  */
      deleted = true;
@@ -2818,6 +2820,8 @@ deduce_inheriting_ctor (tree decl)
        TREE_TYPE (clone) = build_exception_variant (TREE_TYPE (clone), spec);
        SET_DECL_INHERITED_CTOR (clone, inh);
      }
+
+  return true;
  }
/* Implicitly declare the special function indicated by KIND, as a
@@ -2993,9 +2997,17 @@ implicitly_declare_fn (special_function_kind kind, tree 
type,
        if (raises != error_mark_node)
        fn_type = build_exception_variant (fn_type, raises);
        else
-       /* Can happen, eg, in C++98 mode for an ill-formed non-static data
-          member initializer (c++/89914).  */
-       gcc_assert (seen_error ());
+       {
+         /* Can happen, e.g., in C++98 mode for an ill-formed non-static data
+            member initializer (c++/89914).  Also, in C++98, we might have
+            failed to deduce RAISES, so try again but complain this time.  */
+         if (cxx_dialect < cxx11)
+           synthesized_method_walk (type, kind, const_p, nullptr, nullptr,
+                                    nullptr, nullptr, /*diag=*/true,
+                                    &inherited_ctor, inherited_parms);
+         /* We should have seen an error at this point.  */
+         gcc_assert (seen_error ());
+       }
      }
    fn = build_lang_decl (FUNCTION_DECL, name, fn_type);
    if (kind != sfk_inheriting_constructor)
diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor37.C 
b/gcc/testsuite/g++.dg/cpp0x/inh-ctor37.C
new file mode 100644
index 00000000000..7d12b534d95
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor37.C
@@ -0,0 +1,26 @@
+// PR c++/94751
+// { dg-do compile }
+// { dg-options "-w" }
+
+struct A {
+  A(float);
+};
+
+template<typename T>
+struct B : A {
+  using A::A;
+
+  struct C {
+    C(int);
+  };
+
+  C c{ "foo" }; // { dg-error "invalid conversion" }
+};
+
+struct S { S(B<A> *); };
+
+S
+fn ()
+{
+  return S(new B<A>(10.5)); // { dg-error "no matching function" "" { target 
c++98_only } }
+}

base-commit: 812230c63c3efcf2cb36965fe178420b5f1892a6


Reply via email to