https://gcc.gnu.org/g:f5ef1f9e8589697086c8cfea6ad07d56050dde96

commit r15-7417-gf5ef1f9e8589697086c8cfea6ad07d56050dde96
Author: Marek Polacek <pola...@redhat.com>
Date:   Thu Feb 6 08:57:22 2025 -0500

    c++: ICE with unparsed noexcept [PR117106]
    
    In a member-specification of a class, a noexcept-specifier is
    a complete-class context.  Thus we delay parsing until the end of
    the class via our DEFERRED_PARSE mechanism; see cp_parser_save_noexcept
    and cp_parser_late_noexcept_specifier.
    
    We also attempt to defer instantiation of noexcept-specifiers in order
    to reduce the number of instantiations; this is done via DEFERRED_NOEXCEPT.
    
    We can even have both, as in noexcept65.C: a DEFERRED_PARSE wrapped in
    DEFERRED_NOEXCEPT, which uses the DEFPARSE_INSTANTIATIONS mechanism.
    noexcept65.C works, because when we really need the noexcept, which is
    when parsing the body of S::A::A(), the noexcept will have been parsed
    already; noexcepts are parsed before bodies of member function.
    
    But in this test we have:
    
      struct A {
          int x;
          template<class>
          void foo() noexcept(noexcept(x)) {}
          auto bar() -> decltype(foo<int>()) {} // #1
      };
    
    and I think the decltype in #1 needs the unparsed noexcept before it
    could have been parsed.  clang++ rejects the test and I suppose we
    should reject it as well, rather than crashing on a DEFERRED_PARSE
    in tsubst_expr.
    
            PR c++/117106
            PR c++/118190
    
    gcc/cp/ChangeLog:
    
            * pt.cc (maybe_instantiate_noexcept): Give an error if the noexcept
            hasn't been parsed yet.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/cpp0x/noexcept89.C: New test.
            * g++.dg/cpp0x/noexcept90.C: New test.
    
    Reviewed-by: Jason Merrill <ja...@redhat.com>

Diff:
---
 gcc/cp/pt.cc                            | 16 +++++++++++-----
 gcc/testsuite/g++.dg/cpp0x/noexcept89.C |  9 +++++++++
 gcc/testsuite/g++.dg/cpp0x/noexcept90.C | 12 ++++++++++++
 3 files changed, 32 insertions(+), 5 deletions(-)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 39232b5e67fd..8108bf5de655 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -27453,7 +27453,8 @@ maybe_instantiate_noexcept (tree fn, tsubst_flags_t 
complain)
     {
       static hash_set<tree>* fns = new hash_set<tree>;
       bool added = false;
-      if (DEFERRED_NOEXCEPT_PATTERN (noex) == NULL_TREE)
+      tree pattern = DEFERRED_NOEXCEPT_PATTERN (noex);
+      if (pattern == NULL_TREE)
        {
          spec = get_defaulted_eh_spec (fn, complain);
          if (spec == error_mark_node)
@@ -27464,13 +27465,19 @@ maybe_instantiate_noexcept (tree fn, tsubst_flags_t 
complain)
       else if (!(added = !fns->add (fn)))
        {
          /* If hash_set::add returns true, the element was already there.  */
-         location_t loc = cp_expr_loc_or_loc (DEFERRED_NOEXCEPT_PATTERN (noex),
-                                           DECL_SOURCE_LOCATION (fn));
+         location_t loc = cp_expr_loc_or_loc (pattern,
+                                              DECL_SOURCE_LOCATION (fn));
          error_at (loc,
                    "exception specification of %qD depends on itself",
                    fn);
          spec = noexcept_false_spec;
        }
+      else if (TREE_CODE (pattern) == DEFERRED_PARSE)
+       {
+         error ("exception specification of %qD is not available "
+                "until end of class definition", fn);
+         spec = noexcept_false_spec;
+       }
       else if (push_tinst_level (fn))
        {
          const bool push_to_top = maybe_push_to_top_level (fn);
@@ -27497,8 +27504,7 @@ maybe_instantiate_noexcept (tree fn, tsubst_flags_t 
complain)
            ++processing_template_decl;
 
          /* Do deferred instantiation of the noexcept-specifier.  */
-         noex = tsubst_expr (DEFERRED_NOEXCEPT_PATTERN (noex),
-                             DEFERRED_NOEXCEPT_ARGS (noex),
+         noex = tsubst_expr (pattern, DEFERRED_NOEXCEPT_ARGS (noex),
                              tf_warning_or_error, fn);
          /* Build up the noexcept-specification.  */
          spec = build_noexcept_spec (noex, tf_warning_or_error);
diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept89.C 
b/gcc/testsuite/g++.dg/cpp0x/noexcept89.C
new file mode 100644
index 000000000000..308abf6fb455
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/noexcept89.C
@@ -0,0 +1,9 @@
+// PR c++/117106
+// { dg-do compile { target c++11 } }
+
+struct A {
+    int x;
+    template<class>
+    void foo() noexcept(noexcept(x)) {}
+    auto bar() -> decltype(foo<int>()) {} // { dg-error "not available until 
end of class" }
+};
diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept90.C 
b/gcc/testsuite/g++.dg/cpp0x/noexcept90.C
new file mode 100644
index 000000000000..6d403f66e72b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/noexcept90.C
@@ -0,0 +1,12 @@
+// PR c++/118190
+// { dg-do compile { target c++11 } }
+
+struct S {
+  template<typename T>
+  struct S5 {
+    void f1() noexcept(noexcept(i)) { }
+    int i;
+  };
+  S5<int> s5;
+  static_assert (noexcept(s5.f1()), ""); // { dg-error "not available until 
end of class|static assertion failed" }
+};

Reply via email to