Bug 117106 - [12/13/14/15 Regression] ICE when a "deducing this" function with noexcept specification is used before the class is complete
Summary: [12/13/14/15 Regression] ICE when a "deducing this" function with noexcept sp...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 15.0
: P2 normal
Target Milestone: 12.5
Assignee: Marek Polacek
URL:
Keywords: diagnostic, ice-on-invalid-code
Depends on:
Blocks:
 
Reported: 2024-10-12 13:39 UTC by Egor
Modified: 2025-02-07 14:10 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2024-10-22 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Egor 2024-10-12 13:39:05 UTC
The following code causes an internal compiler error in GCC 14 and trunk: https://gcc.godbolt.org/z/j5Y945fMq

    struct A
    {
        int x;
        void foo(this auto &&self) noexcept(noexcept(self.x)) {}
        auto bar() -> decltype(foo()) {}
    };

This results in the following error:

    <source>: In instantiation of 'void A::foo(this auto:1&&) [with auto:1 = A&]':
    <source>:5:35:   required from here
        5 |         auto bar() -> decltype(foo()) {}
        |                                ~~~^~
    <source>:4:14: internal compiler error: in tsubst_expr, at cp/pt.cc:21978
        4 |         void foo(this auto &&self) noexcept(noexcept(self.x)) {}
        |              ^~~
    0x285c505 diagnostic_context::diagnostic_impl(rich_location*, diagnostic_metadata const*, diagnostic_option_id, char const*, __va_list_tag (*) [1], diagnostic_t)
        ???:0
    0x28702e5 internal_error(char const*, ...)
        ???:0
    0xa8b484 fancy_abort(char const*, int, char const*)
        ???:0
    0xccfed2 maybe_instantiate_noexcept(tree_node*, int)
        ???:0
    0xb8c2ea mark_used(tree_node*, int)
        ???:0
    0xab6458 build_new_method_call(tree_node*, tree_node*, vec<tree_node*, va_gc, vl_embed>**, tree_node*, int, tree_node**, int)
        ???:0
    0xd17106 finish_call_expr(tree_node*, vec<tree_node*, va_gc, vl_embed>**, bool, bool, int)
        ???:0
    0xc989da c_parse_file()
        ???:0
    0xdf0599 c_common_parse_file()
        ???:0

Worth noting that Clang emits a weird error on this code: https://stackoverflow.com/q/79081096/2752075

    error: exception specification is not available until end of class definition
Comment 1 Fedor Chelnokov 2024-10-12 20:05:19 UTC
This crash is reproducible in C++20 mode as well without deducing this:
```
struct A {
    int x;
    void foo(this auto &&self) noexcept(noexcept(self.x)) {}
    auto bar() -> decltype(foo()) {}
};
```
In instantiation of 'void A::foo() [with <template-parameter-1-1> = int]':
<source>:5:36:   required from here
    5 |     auto bar() -> decltype(foo<int>()) {}
      |                            ~~~~~~~~^~
<source>:4:10: internal compiler error: Segmentation fault
    4 |     void foo() noexcept(noexcept(x)) {}
      |          ^~~
0x2031cbc internal_error(char const*, ...)
	???:0
0x11fb4f4 check_qualified_type(tree_node const*, tree_node const*, int)
	???:0
0x11fb5f3 get_qualified_type(tree_node*, int)
	???:0
0x1206345 build_qualified_type(tree_node*, int)
	???:0
0x843cba build_noexcept_spec(tree_node*, int)
	???:0
0x9301e1 maybe_instantiate_noexcept(tree_node*, int)
	???:0
0x83311a mark_used(tree_node*, int)
	???:0
0x79d629 build_new_method_call(tree_node*, tree_node*, vec<tree_node*, va_gc, vl_embed>**, tree_node*, int, tree_node**, int)
	???:0
0x960c3c finish_call_expr(tree_node*, vec<tree_node*, va_gc, vl_embed>**, bool, bool, int)
	???:0
0x90ee14 c_parse_file()
	???:0
0xa0d1b9 c_common_parse_file()
	???:0

Online demo: https://gcc.godbolt.org/z/PW6sn8Tjq
Comment 2 Marek Polacek 2024-10-22 20:50:13 UTC
Started with r12-6025 so mine.

commit 06041b2c67a5d4d0941c53990f0438a309703ed0
Author: Marek Polacek <polacek@redhat.com>
Date:   Wed Dec 15 17:41:53 2021 -0500

    c++: delayed noexcept in member function template [PR99980]
Comment 3 Fedor Chelnokov 2024-10-22 21:26:26 UTC
(comment #1 corrected)
> This crash is reproducible in C++20 mode as well without deducing this:
```
struct A {
    int x;
    template<class>
    void foo() noexcept(noexcept(x)) {}
    auto bar() -> decltype(foo<int>()) {}
};
```
Comment 4 GCC Commits 2025-02-07 14:04:59 UTC
The trunk branch has been updated by Marek Polacek <mpolacek@gcc.gnu.org>:

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

commit r15-7417-gf5ef1f9e8589697086c8cfea6ad07d56050dde96
Author: Marek Polacek <polacek@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 <jason@redhat.com>
Comment 5 Marek Polacek 2025-02-07 14:10:42 UTC
Fixed for 15.