Given the following, GCC says: "error: invalid use of 'this' at top level" However, according to [expr.prim.general]/3 'this' should be valid in the exception-specification as it comes after the member function's optional cv-qualifier-seq. #define RETURNS(...) noexcept(noexcept(__VA_ARGS__)) -> decltype(__VA_ARGS__) { return (__VA_ARGS__); } struct mul_ { int operator()() const { return 1; } template <typename A> A operator()(A const & a) const noexcept(A(std::move(a))) { return a; } template <typename A, typename B, typename... C> auto operator()(A const & a, B const & b, C const &... c) const RETURNS((*this)(a * b, c...)) };
#include <iostream> using namespace std; class A { public: void g() noexcept(false) {} void f() noexcept( noexcept( g() )) {}; }; A a; int main() { cout<<noexcept(a.f())<<endl; return 0; } This is another testcase.
Simpler test case: struct S { void f() noexcept(noexcept(this)) {} }; int main() {} Updated standard reference stating that this should be valid: http://eel.is/c++draft/expr.prim.this#2
Any news on this? It is making writing noexcept specifications very hard since 2012...
*** Bug 78301 has been marked as a duplicate of this bug. ***
Testcase for both problems: struct S { void f() { } void g() noexcept(noexcept(f())) { } void h() noexcept(noexcept(this->f())) { } }; ne.cc:3:34: error: cannot call member function ‘void S::f()’ without object void g() noexcept(noexcept(f())) { } ^ ne.cc:4:32: error: invalid use of ‘this’ at top level void h() noexcept(noexcept(this->f())) { } ^~~~
Reproduced in 8.1.1: $ cat nyan.cpp struct Nyan { constexpr Nyan &operator++() noexcept { return *this; } constexpr void omg() noexcept(noexcept(++*this)) {} }; int main() {} $ g++ -Wall -Wextra nyan.cpp nyan.cpp:3:44: error: invalid use of ‘this’ at top level constexpr void omg() noexcept(noexcept(++*this)) {} ^~~~ $ clang++ nyan.cpp $ g++ -v Using built-in specs. COLLECT_GCC=g++ COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-linux-gnu/8.1.1/lto-wrapper Target: x86_64-pc-linux-gnu Configured with: /build/gcc/src/gcc/configure --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://bugs.archlinux.org/ --enable-languages=c,c++,ada,fortran,go,lto,objc,obj-c++ --enable-shared --enable-threads=posix --enable-libmpx --with-system-zlib --with-isl --enable-__cxa_atexit --disable-libunwind-exceptions --enable-clocale=gnu --disable-libstdcxx-pch --disable-libssp --enable-gnu-unique-object --enable-linker-build-id --enable-lto --enable-plugin --enable-install-libiberty --with-linker-hash-style=gnu --enable-gnu-indirect-function --enable-multilib --disable-werror --enable-checking=release --enable-default-pie --enable-default-ssp Thread model: posix gcc version 8.1.1 20180531 (GCC) $ uname -a Linux home 4.17.10-1-ARCH #1 SMP PREEMPT Wed Jul 25 11:23:00 UTC 2018 x86_64 GNU/Linux
cat test.cpp ========================================================================== #define _NOEXCEPT_OP(x) noexcept(x) template<class _Ty> inline bool _Swap_adl(_Ty& _Left, _Ty& _Right) { return (true); } template<class _Ty1, class _Ty2> struct pair { typedef pair<_Ty1, _Ty2> _Myt; typedef _Ty1 first_type; typedef _Ty2 second_type; void swap(_Myt& _Right) _NOEXCEPT_OP(_NOEXCEPT_OP(_Swap_adl(this->first, _Right.first)) && _NOEXCEPT_OP(_Swap_adl(this->second, _Right.second))) { if (this != &_Right) { // different, worth swapping _Swap_adl(first, _Right.first); _Swap_adl(second, _Right.second); } } _Ty1 first; _Ty2 second; }; ========================================================================== g++ test.cpp -c test.cpp:18:39: error: invalid use of ‘this’ at top level test.cpp:19:30: error: invalid use of ‘this’ at top level Same issue with the current upstream sources as well. Please let me know if there is any patch or workaround to fix the issue. Else please let me know how to fix this issue in GCC. Thanks
the following patch fix all the reported cases and tested with latest trunk and 8.1 source i.e Index: gcc/cp/parser.c =================================================================== --- gcc/cp/parser.c (revision 266026) +++ gcc/cp/parser.c (working copy) @@ -24615,6 +24615,8 @@ { tree expr; cp_lexer_consume_token (parser->lexer); + + inject_this_parameter (current_class_type, TYPE_UNQUALIFIED); if (cp_lexer_peek_token (parser->lexer)->type == CPP_OPEN_PAREN) { ok to commit ?
Please send the patch to gcc-patches@gcc.gnu.org for review.
Author: jason Date: Fri Nov 16 21:55:00 2018 New Revision: 266224 URL: https://gcc.gnu.org/viewcvs?rev=266224&root=gcc&view=rev Log: PR c++/52869 DR 1207 * parser.c (cp_parser_noexcept_specification_opt): Call inject_this_parameter. Added: trunk/gcc/testsuite/g++.dg/DRs/dr1207-1.C trunk/gcc/testsuite/g++.dg/DRs/dr1207-2.C Modified: trunk/gcc/cp/ChangeLog trunk/gcc/cp/parser.c
Thank you Jason and Marek for all your support .
The exception specification seems to be processed too early, before the other class members are in scope. This slight variation of comment 5 still fails on trunk: struct S { void g() noexcept(noexcept(f())) { } void h() noexcept(noexcept(this->f())) { } void f() { } }; 2869.cc:2:32: error: 'f' was not declared in this scope 2 | void g() noexcept(noexcept(f())) { } | ^ 52869.cc:3:38: error: 'struct S' has no member named 'f' 3 | void h() noexcept(noexcept(this->f())) { } | ^
Thanks Jon, I'll poke at it some more.
This is actually another problem, one that is tracked in PR86476.
(In reply to Marek Polacek from comment #14) > This is actually another problem, one that is tracked in PR86476. So context closure is unduly greedy: members defined above are available while those from below are not? Funny indeed.
(In reply to Marek Polacek from comment #14) > This is actually another problem, one that is tracked in PR86476. Hmm. $ cat wat.cpp struct Omg { void f() {} void g() noexcept(noexcept(f())) {} }; $ g++ wat.cpp wat.cpp:3:31: error: cannot call member function ‘void Omg::f()’ without object void g() noexcept(noexcept(f())) {} ^ $ g++ -v |& grep version gcc version 8.2.1 20181127 (GCC)
(In reply to denin from comment #16) > (In reply to Marek Polacek from comment #14) > > This is actually another problem, one that is tracked in PR86476. > > Hmm. > > $ cat wat.cpp > struct Omg { > void f() {} > void g() noexcept(noexcept(f())) {} > }; > $ g++ wat.cpp > wat.cpp:3:31: error: cannot call member function ‘void Omg::f()’ without > object > void g() noexcept(noexcept(f())) {} > ^ > $ g++ -v |& grep version > gcc version 8.2.1 20181127 (GCC) This is what the commit in Comment 10 fixed; it has only been fixed for GCC 9.
Author: mpolacek Date: Sat Jun 22 15:14:30 2019 New Revision: 272586 URL: https://gcc.gnu.org/viewcvs?rev=272586&root=gcc&view=rev Log: PR c++/86476 - noexcept-specifier is a complete-class context. PR c++/52869 * cp-tree.def (DEFAULT_ARG): Update commentary. * cp-tree.h (UNPARSED_NOEXCEPT_SPEC_P): New macro. (tree_default_arg): Use tree_base instead of tree_common. (do_push_parm_decls, maybe_check_overriding_exception_spec): Declare. * decl.c (do_push_parm_decls): New function, broken out of... (store_parm_decls): ...here. Call it. * except.c (nothrow_spec_p): Accept DEFAULT_ARG in the assert. * parser.c (cp_parser_noexcept_specification_opt, cp_parser_late_noexcept_specifier, noexcept_override_late_checks): Forward-declare. (unparsed_noexcepts): New macro. (push_unparsed_function_queues): Update initializer. (cp_parser_direct_declarator): Pass FRIEND_P to cp_parser_exception_specification_opt. (inject_parm_decls): New. (pop_injected_parms): New. (cp_parser_class_specifier_1): Implement delayed parsing of noexcept-specifiers. (cp_parser_save_noexcept): New. (cp_parser_late_noexcept_specifier): New. (noexcept_override_late_checks): New. (cp_parser_noexcept_specification_opt): Add FRIEND_P parameter. Call cp_parser_save_noexcept instead of the normal processing if needed. (cp_parser_exception_specification_opt): Add FRIEND_P parameter and pass it to cp_parser_noexcept_specification_opt. (cp_parser_save_member_function_body): Fix comment. (cp_parser_save_default_args): Maybe save the noexcept-specifier to post process. (cp_parser_transaction): Update call to cp_parser_noexcept_specification_opt. (cp_parser_transaction_expression): Likewise. * parser.h (cp_unparsed_functions_entry): Add new field to carry a noexcept-specifier. * pt.c (dependent_type_p_r): Handle unparsed noexcept expression. * search.c (maybe_check_overriding_exception_spec): New function, broken out of... (check_final_overrider): ...here. Call maybe_check_overriding_exception_spec. * tree.c (canonical_eh_spec): Handle UNPARSED_NOEXCEPT_SPEC_P. (cp_tree_equal): Handle DEFAULT_ARG. * g++.dg/cpp0x/noexcept45.C: New test. * g++.dg/cpp0x/noexcept46.C: New test. * g++.dg/cpp0x/noexcept47.C: New test. * g++.dg/cpp0x/noexcept48.C: New test. * g++.dg/cpp0x/noexcept49.C: New test. * g++.dg/cpp0x/noexcept50.C: New test. * g++.dg/cpp0x/noexcept51.C: New test. * g++.dg/cpp0x/noexcept52.C: New test. * g++.dg/cpp0x/noexcept53.C: New test. * g++.dg/eh/shadow1.C: Adjust dg-error. Added: trunk/gcc/testsuite/g++.dg/cpp0x/noexcept45.C trunk/gcc/testsuite/g++.dg/cpp0x/noexcept46.C trunk/gcc/testsuite/g++.dg/cpp0x/noexcept47.C trunk/gcc/testsuite/g++.dg/cpp0x/noexcept48.C trunk/gcc/testsuite/g++.dg/cpp0x/noexcept49.C trunk/gcc/testsuite/g++.dg/cpp0x/noexcept50.C trunk/gcc/testsuite/g++.dg/cpp0x/noexcept51.C trunk/gcc/testsuite/g++.dg/cpp0x/noexcept52.C trunk/gcc/testsuite/g++.dg/cpp0x/noexcept53.C Modified: trunk/gcc/cp/ChangeLog trunk/gcc/cp/cp-tree.def trunk/gcc/cp/cp-tree.h trunk/gcc/cp/decl.c trunk/gcc/cp/except.c trunk/gcc/cp/parser.c trunk/gcc/cp/parser.h trunk/gcc/cp/pt.c trunk/gcc/cp/search.c trunk/gcc/cp/tree.c trunk/gcc/testsuite/ChangeLog trunk/gcc/testsuite/g++.dg/eh/shadow1.C
Fixed.
Seems some variant of this bug has returned with g++-11 (but not in g++-10) $ cat s.cpp struct S { void f() noexcept {} S &g() noexcept(noexcept(f())) { f(); return *this; } }; $ g++-11 -Wall -Werror -std=c++2a -c s.cpp s.cpp:4:31: error: cannot call member function 'void S::f()' without object 4 | S &g() noexcept(noexcept(f())) { f(); return *this; } | ~^~ $ cat s.cpp struct S { void f() noexcept {} S &g() noexcept(noexcept(this->f())) { f(); return *this; } }; $ g++-11 -Wall -Werror -std=c++2a -c s.cpp s.cpp:4:30: error: invalid use of 'this' at top level 4 | S &g() noexcept(noexcept(this->f())) { f(); return *this; } | ^~~~ $ cat workaround.cpp struct S { void f() noexcept {} auto g() noexcept(noexcept(this->f())) -> S& { f(); return *this; } }; $ g++-11 -Wall -Werror -std=c++2a -c workaround.cpp $ g++-11 -v Using built-in specs. COLLECT_GCC=g++-11 COLLECT_LTO_WRAPPER=/usr/local/Cellar/gcc/11.1.0/libexec/gcc/x86_64-apple-darwin19/11.1.0/lto-wrapper Target: x86_64-apple-darwin19 Configured with: ../configure --prefix=/usr/local/Cellar/gcc/11.1.0 --libdir=/usr/local/Cellar/gcc/11.1.0/lib/gcc/11 --disable-nls --enable-checking=release --enable-languages=c,c++,objc,obj-c++,fortran,d --program-suffix=-11 --with-gmp=/usr/local/opt/gmp --with-mpfr=/usr/local/opt/mpfr --with-mpc=/usr/local/opt/libmpc --with-isl=/usr/local/opt/isl --with-pkgversion='Homebrew GCC 11.1.0' --with-bugurl=https://github.com/Homebrew/homebrew-core/issues --enable-libphobos --build=x86_64-apple-darwin19 --with-system-zlib --disable-multilib --with-native-system-header-dir=/usr/include --with-sysroot=/Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk Thread model: posix Supported LTO compression algorithms: zlib gcc version 11.1.0 (Homebrew GCC 11.1.0) ~ $ uname -a Darwin home.local 19.6.0 Darwin Kernel Version 19.6.0: Mon Apr 12 20:57:45 PDT 2021; root:xnu-6153.141.28.1~1/RELEASE_X86_64 x86_64
Oh dear. It started to fail with r11-289. I've created Bug 100752.