Bug 94117 - deferred noexcept specifications and friend fns
Summary: deferred noexcept specifications and friend fns
Status: SUSPENDED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 10.0
: P3 normal
Target Milestone: ---
Assignee: Nathan Sidwell
URL:
Keywords: accepts-invalid
Depends on:
Blocks: c++-friends, cxxfriends
  Show dependency treegraph
 
Reported: 2020-03-10 10:37 UTC by Nathan Sidwell
Modified: 2024-03-25 23:50 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2020-03-10 00:00:00


Attachments
distilled from ranges (151 bytes, text/plain)
2020-03-10 10:37 UTC, Nathan Sidwell
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Nathan Sidwell 2020-03-10 10:37:58 UTC
Created attachment 48006 [details]
distilled from ranges

We accept the attached test case, which should be rejected.
It comes from these two fragments of the ranges header:

lines ~1595
	  static constexpr decltype(auto)
	  __iter_move(const _Iterator& __i = {})
	    noexcept(noexcept(std::__invoke(*__i._M_parent->_M_fun,
					    *__i._M_current)))
	  {
	    if constexpr (is_lvalue_reference_v<decltype(*__i)>)
	      return std::move(*__i);
	    else
	      return *__i;
	  }

lines ~1752
	  friend constexpr decltype(auto)
	  iter_move(const _Iterator& __i) noexcept(noexcept(__iter_move()))
	  { return __iter_move(__i); }

If we change __iter_move's argument type to int, we reject complaining that the call in iter_move's noexcept spec requires the default argument before it's been parsed.  Clang rejects either way.

the '__iter_move ()' call is not dependent because it has no arguments.  Addition of the default argument does not make it dependent.

filing a separate issue to fix libstdc++
Comment 1 Jakub Jelinek 2020-03-10 10:40:19 UTC
Related or dup of PR93901 ?  Guess I'll bisect to see if it is the same commit.
Comment 2 Jakub Jelinek 2020-03-10 10:44:57 UTC
Maybe not, as it doesn't seem to be a regression, it has never been rejected (at least not in anything since r200000 I've tried).
clang++ rejects with
exception specification is not available until end of class definition
Comment 3 Nathan Sidwell 2020-03-10 10:47:18 UTC
This is the error that should be emitted (modulo the argument type being _Iterator)

devvm2772:6>./cc1plus -fmodule-header -quiet b_a.H
In file included from b_a.H:1:
b.h:10:69: error: call to 'static void _Iterator<_Const>::mover(const int&)' uses the default argument for parameter 1, which is not yet defined
   10 |   friend void move (const _Iterator &arg) noexcept (noexcept (mover ()))
Comment 4 Jonathan Wakely 2020-03-10 11:41:19 UTC
(In reply to Nathan Sidwell from comment #0)
> filing a separate issue to fix libstdc++

Fixed in r10-7103-gc222eabcf8be0e3f644e4bd4c3316b40dba4b514

    libstdc++: Fix invalid noexcept-specifier (PR 94117)
    
    G++ fails to diagnose this non-dependent expression, but Clang doesn't
    like it.
    
            PR c++/94117
            * include/std/ranges (ranges::transform_view::_Iterator::iter_move):
            Change expression in noexcept-specifier to match function body.
Comment 5 Jonathan Wakely 2020-03-10 11:54:57 UTC
Oh we have more occurrences of it in libstdc++, e.g. in split_view

	  friend constexpr decltype(auto)
	  iter_move(const _InnerIter& __i) noexcept(noexcept(__iter_move()))
	  { return __iter_move(__i); }

	  friend constexpr void
	  iter_swap(const _InnerIter& __x, const _InnerIter& __y)
	    noexcept(noexcept(__iter_swap()))
	    requires indirectly_swappable<iterator_t<_Base>>
	  { __iter_swap(__x, __y); }
Comment 6 Nathan Sidwell 2020-03-10 14:28:17 UTC
Ah, I understand what is happening.  

We don't defer parsing of the noexcept specified of friend functions.  That leads us to construct a base-link expr whose type contains the deferred parse exception specification of the *static* member function -- there being only one, it doesn't get unknown type.

In processing the deferred exception specification of that fn, we don't fixup all the type variants that might have been created.

There's a restriction on friend declarations that contain default args.  This is the same problem that is trying to avoid.
Comment 7 Marek Polacek 2020-03-10 14:52:31 UTC
Yes, it was a conscious decision not to defer parsing of noexcept-spec of friend functions.  The standard currently doesn't say we shouldn't defer, but no compiler implements it.  The problem was that friend declarations can be redeclared and it would be tricky to see if their noexcept-specs match.
Comment 8 Jonathan Wakely 2020-03-11 09:20:30 UTC
(In reply to Jonathan Wakely from comment #5)
> Oh we have more occurrences of it in libstdc++, e.g. in split_view

Fixed in r10-7108-gcf0c3a457319df1e8dc9321227162a7c57169a39
Comment 9 Nathan Sidwell 2020-03-11 09:59:45 UTC
Discussing on the core list  https://lists.isocpp.org/core/2020/03/8632.php (password required)

I have a fix the the problem I encountered on the modules branch.  Not suitable at this stage for trunk, and there's probably a better solution out there.

As Marek says 'nobody implements this'
Comment 10 Martin Liška 2020-03-11 12:05:55 UTC
commit r10-7103-gc222eabcf8be0e3f644e4bd4c3316b40dba4b514
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Tue Mar 10 10:50:40 2020 +0000

    libstdc++: Fix invalid noexcept-specifier (PR 94117)
    
    G++ fails to diagnose this non-dependent expression, but Clang doesn't
    like it.
    
            PR c++/94117
            * include/std/ranges (ranges::transform_view::_Iterator::iter_move):
            Change expression in noexcept-specifier to match function body.