https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108490
--- Comment #8 from Jonathan Wakely <redi at gcc dot gnu.org> --- (In reply to Jakub Jelinek from comment #5) > (In reply to Jonathan Wakely from comment #2) > > Yes. The attribute has to be there, so it's a Circle bug if it doesn't > > support that grammar. > > Why can't it be before the friend specifier? > template<typename _It2, sentinel_for<_It> _Sent2> > requires sentinel_for<_Sent, _It2> > [[nodiscard]] friend constexpr bool > operator== (const common_iterator& __x, > const common_iterator<_It2, _Sent2>& __y) > { > ... > } > I mean, at least > struct S > { > template <typename T> > friend constexpr bool foo [[nodiscard]] (const S &, const T &) { return > true; } > template <typename T> > [[nodiscard]] friend constexpr bool bar (const S &, const T &) { return > true; } The problem is an ambiguity in the grammar for the requires-clause, and this example doesn't have any requires-clause. Try: template <typename T> requires C<T> [[nodiscard]] friend constexpr bool bar (const S &, const T &) { return true; } And then compile with -fconcepts-ts f.cc:7:3: error: two consecutive '[' shall only introduce an attribute before '[' token 7 | [[nodiscard]] friend constexpr bool bar (const S &, const T &) { return true; } | ^ See PR101782 where you figured out the problem in the grammar :-) The libstdc++ code is not written that way because I *like* putting the attribute in that position, but because it's necessary. And it's valid C++, so this is a Circle bug.