public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug c++/101904] New: Wrong result of decltype during instantiation of std::result_of
@ 2021-08-13 20:22 officesamurai at gmail dot com
2021-08-15 6:49 ` [Bug c++/101904] " redi at gcc dot gnu.org
` (7 more replies)
0 siblings, 8 replies; 9+ messages in thread
From: officesamurai at gmail dot com @ 2021-08-13 20:22 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101904
Bug ID: 101904
Summary: Wrong result of decltype during instantiation of
std::result_of
Product: gcc
Version: 11.2.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: officesamurai at gmail dot com
Target Milestone: ---
gcc_wrong_decltype.cpp:
---
#include <type_traits>
struct ZZZ
{
template <typename Func>
auto foo(Func func) -> std::result_of_t<Func(int*)>
{
return func(static_cast<int*>(nullptr));
}
template <typename Func>
auto foo(Func func) const -> std::result_of_t<Func(const int*)>
{
return func(static_cast<const int*>(nullptr));
}
};
int main()
{
const ZZZ zzz;
zzz.foo(
[&](auto* pointer)
// specifying the return type explicitly will fix the issue
//-> void
{
static_assert(std::is_same_v<decltype(pointer), const int*>, "");
});
}
---
Compiler invocation:
---
$ g++-11.2.0 -c gcc_wrong_decltype.cpp
gcc_wrong_decltype.cpp: In instantiation of ‘main()::<lambda(auto:1*)> [with
auto:1 = int]’:
/home/brd/soft/gcc-11.2.0/include/c++/11.2.0/type_traits:2466:26: required by
substitution of ‘template<class _Fn, class ... _Args> static
std::__result_of_success<decltype (declval<_Fn>()((declval<_Args>)()...)),
std::__invoke_other> std::__result_of_other_impl::_S_test(int) [with _Fn =
main()::<lambda(auto:1*)>; _Args = {int*}]’
/home/brd/soft/gcc-11.2.0/include/c++/11.2.0/type_traits:2477:55: required
from ‘struct std::__result_of_impl<false, false, main()::<lambda(auto:1*)>,
int*>’
/home/brd/soft/gcc-11.2.0/include/c++/11.2.0/type_traits:2482:12: required
from ‘struct std::__invoke_result<main()::<lambda(auto:1*)>, int*>’
/home/brd/soft/gcc-11.2.0/include/c++/11.2.0/type_traits:2495:12: required
from ‘struct std::result_of<main()::<lambda(auto:1*)>(int*)>’
/home/brd/soft/gcc-11.2.0/include/c++/11.2.0/type_traits:2530:11: required by
substitution of ‘template<class _Tp> using result_of_t = typename
std::result_of::type [with _Tp = main()::<lambda(auto:1*)>(int*)]’
gcc_wrong_decltype.cpp:6:10: required by substitution of ‘template<class
Func> std::result_of_t<Func(int*)> ZZZ::foo(Func) [with Func =
main()::<lambda(auto:1*)>]’
gcc_wrong_decltype.cpp:22:12: required from here
gcc_wrong_decltype.cpp:27:32: error: static assertion failed
27 | static_assert(std::is_same_v<decltype(pointer), const
int*>, "");
| ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
gcc_wrong_decltype.cpp:27:32: note: ‘std::is_same_v<int*, const int*>’
evaluates to false
---
Note that 'pointer' actually points to const int (it's impossible to modify the
pointee). Also, explicitly specifying the return type for the lambda fixes the
issue.
Compiler version:
---
g++-11.2.0 -v
Using built-in specs.
COLLECT_GCC=g++-11.2.0
COLLECT_LTO_WRAPPER=/home/brd/soft/gcc-11.2.0/libexec/gcc/x86_64-pc-linux-gnu/11.2.0/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: ./configure --prefix=/home/brd/soft/gcc-11.2.0
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 11.2.0 (GCC)
---
But the same happens with 10.3.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* [Bug c++/101904] Wrong result of decltype during instantiation of std::result_of
2021-08-13 20:22 [Bug c++/101904] New: Wrong result of decltype during instantiation of std::result_of officesamurai at gmail dot com
@ 2021-08-15 6:49 ` redi at gcc dot gnu.org
2021-08-15 20:42 ` officesamurai at gmail dot com
` (6 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: redi at gcc dot gnu.org @ 2021-08-15 6:49 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101904
Jonathan Wakely <redi at gcc dot gnu.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
Status|UNCONFIRMED |RESOLVED
Resolution|--- |INVALID
--- Comment #1 from Jonathan Wakely <redi at gcc dot gnu.org> ---
Not a bug. The call to zzz.foo had to do overload resolution to decide which
foo to call. That means both result_of types get instantiated. That means the
lambda gets instantiated with an argument of int* as well as with an argument
of const int*. Without an explicit return type the body of the lambda is
instantiated, which fails the static_assert for the int* case
^ permalink raw reply [flat|nested] 9+ messages in thread
* [Bug c++/101904] Wrong result of decltype during instantiation of std::result_of
2021-08-13 20:22 [Bug c++/101904] New: Wrong result of decltype during instantiation of std::result_of officesamurai at gmail dot com
2021-08-15 6:49 ` [Bug c++/101904] " redi at gcc dot gnu.org
@ 2021-08-15 20:42 ` officesamurai at gmail dot com
2021-08-17 9:57 ` redi at gcc dot gnu.org
` (5 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: officesamurai at gmail dot com @ 2021-08-15 20:42 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101904
--- Comment #2 from Mikhail Kremniov <officesamurai at gmail dot com> ---
I see, thanks.
But I must mention that Clang is able to compile this code somehow.
^ permalink raw reply [flat|nested] 9+ messages in thread
* [Bug c++/101904] Wrong result of decltype during instantiation of std::result_of
2021-08-13 20:22 [Bug c++/101904] New: Wrong result of decltype during instantiation of std::result_of officesamurai at gmail dot com
2021-08-15 6:49 ` [Bug c++/101904] " redi at gcc dot gnu.org
2021-08-15 20:42 ` officesamurai at gmail dot com
@ 2021-08-17 9:57 ` redi at gcc dot gnu.org
2021-08-17 15:32 ` redi at gcc dot gnu.org
` (4 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: redi at gcc dot gnu.org @ 2021-08-17 9:57 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101904
--- Comment #3 from Jonathan Wakely <redi at gcc dot gnu.org> ---
Only clang can compile it. MSVC and EDG can't:
https://godbolt.org/z/941P1vfjG
I think Clang doesn't even bother to instantiate the return type for the
non-const overload, because it wouldn't be viable. I'm not sure if that's a
conforming implementation or not.
Reduced:
namespace std
{
template<typename, typename> constexpr bool is_same_v = false;
template<typename T> constexpr bool is_same_v<T, T> = true;
template<typename> using void_t = void;
template<typename T> T&& declval();
template<typename F, typename Arg, typename = void>
struct result_of_impl
{ };
template<typename F, typename Arg>
struct result_of_impl<F, Arg,
void_t<decltype(declval<F>()(declval<Arg>()))>>
{
using type = decltype(declval<F>()(declval<Arg>()));
};
template<typename> struct result_of;
template<typename F, typename Arg>
struct result_of<F(Arg)>
: result_of_impl<F, Arg>
{ };
template<typename T> using result_of_t = typename result_of<T>::type;
}
struct ZZZ
{
template <typename Func>
auto foo(Func func) -> std::result_of_t<Func(int*)>
{
return func(static_cast<int*>(nullptr));
}
template <typename Func>
auto foo(Func func) const -> std::result_of_t<Func(const int*)>
{
return func(static_cast<const int*>(nullptr));
}
};
int main()
{
const ZZZ zzz;
zzz.foo(
[&](auto* pointer)
// specifying the return type explicitly will fix the issue
//-> void
{
static_assert(std::is_same_v<decltype(pointer), const int*>, "");
});
}
^ permalink raw reply [flat|nested] 9+ messages in thread
* [Bug c++/101904] Wrong result of decltype during instantiation of std::result_of
2021-08-13 20:22 [Bug c++/101904] New: Wrong result of decltype during instantiation of std::result_of officesamurai at gmail dot com
` (2 preceding siblings ...)
2021-08-17 9:57 ` redi at gcc dot gnu.org
@ 2021-08-17 15:32 ` redi at gcc dot gnu.org
2021-08-24 3:58 ` ppalka at gcc dot gnu.org
` (3 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: redi at gcc dot gnu.org @ 2021-08-17 15:32 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101904
--- Comment #4 from Jonathan Wakely <redi at gcc dot gnu.org> ---
(In reply to Jonathan Wakely from comment #3)
> I think Clang doesn't even bother to instantiate the return type for the
> non-const overload, because it wouldn't be viable. I'm not sure if that's a
> conforming implementation or not.
[temp.inst] p9:
"If the function selected by overload resolution (12.2) can be determined
without instantiating a class template definition, it is unspecified whether
that instantiation actually takes place."
So the compiler is permitted to skip the result_of instantiation in the return
type if it knows that overload won't be selected anyway. But it's not required
to skip it, so your code is still wrong.
^ permalink raw reply [flat|nested] 9+ messages in thread
* [Bug c++/101904] Wrong result of decltype during instantiation of std::result_of
2021-08-13 20:22 [Bug c++/101904] New: Wrong result of decltype during instantiation of std::result_of officesamurai at gmail dot com
` (3 preceding siblings ...)
2021-08-17 15:32 ` redi at gcc dot gnu.org
@ 2021-08-24 3:58 ` ppalka at gcc dot gnu.org
2021-09-03 15:34 ` cvs-commit at gcc dot gnu.org
` (2 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: ppalka at gcc dot gnu.org @ 2021-08-24 3:58 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101904
Patrick Palka <ppalka at gcc dot gnu.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
CC| |ppalka at gcc dot gnu.org
--- Comment #5 from Patrick Palka <ppalka at gcc dot gnu.org> ---
The validity of this testcase seems closely related to DR1391 which adds an
extra step during template argument deduction for checking the convertibility
of non-dependent function parms/args before instantiating the function
template.
Note that if we turn the two overloads of ZZZ::foo into static member functions
with an explicit 'this' parameter, then both GCC and Clang accept the testcase
as per DR1391:
#include <type_traits>
struct ZZZ
{
template <typename Func>
static auto foo(ZZZ*, Func func) -> std::result_of_t<Func(int*)>
{
return func(static_cast<int*>(nullptr));
}
template <typename Func>
static auto foo(const ZZZ*, Func func) -> std::result_of_t<Func(const
int*)>
{
return func(static_cast<const int*>(nullptr));
}
};
int main()
{
const ZZZ zzz;
ZZZ::foo(&zzz,
[&](auto* pointer)
{
static_assert(std::is_same_v<decltype(pointer), const int*>, "");
});
}
So it looks like Clang applies DR1391 to the implicit 'this' parameter of
member functions, which seems worthwhile for us to do too (though it's not
strictly required for conformance). I'm working on a rough patch to that
effect
^ permalink raw reply [flat|nested] 9+ messages in thread
* [Bug c++/101904] Wrong result of decltype during instantiation of std::result_of
2021-08-13 20:22 [Bug c++/101904] New: Wrong result of decltype during instantiation of std::result_of officesamurai at gmail dot com
` (4 preceding siblings ...)
2021-08-24 3:58 ` ppalka at gcc dot gnu.org
@ 2021-09-03 15:34 ` cvs-commit at gcc dot gnu.org
2021-09-13 15:14 ` ppalka at gcc dot gnu.org
2021-09-15 22:42 ` cvs-commit at gcc dot gnu.org
7 siblings, 0 replies; 9+ messages in thread
From: cvs-commit at gcc dot gnu.org @ 2021-09-03 15:34 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101904
--- Comment #6 from CVS Commits <cvs-commit at gcc dot gnu.org> ---
The master branch has been updated by Patrick Palka <ppalka@gcc.gnu.org>:
https://gcc.gnu.org/g:47543e5f9d1fc502be79f91c87cbeb6eda17e641
commit r12-3346-g47543e5f9d1fc502be79f91c87cbeb6eda17e641
Author: Patrick Palka <ppalka@redhat.com>
Date: Fri Sep 3 11:33:41 2021 -0400
c++: shortcut bad convs during overload resolution [PR101904]
In the context of overload resolution we have the notion of a "bad"
argument conversion, which is a conversion that "would be a permitted
with a bending of the language standards", and we handle such bad
conversions specially. In particular, we rank a bad conversion as
better than no conversion but worse than a good conversion, and a bad
conversion doesn't necessarily make a candidate unviable. With the
flag -fpermissive, we permit the situation where overload resolution
selects a candidate that contains a bad conversion (which we call a
non-strictly viable candidate). And without the flag, the caller
of overload resolution usually issues a distinct permerror in this
situation instead.
One consequence of this defacto behavior is that in order to distinguish
a non-strictly viable candidate from an unviable candidate, if we
encounter a bad argument conversion during overload resolution we must
keep converting subsequent arguments because a subsequent conversion
could render the candidate unviable instead of just non-strictly viable.
But checking subsequent arguments can force template instantiations and
result in otherwise avoidable hard errors. And in particular, all
'this' conversions are at worst bad, so this means the const/ref-qualifiers
of a member function can't be used to prune a candidate quickly, which
is the subject of the mentioned PR.
This patch tries to improve the situation without changing the defacto
output of add_candidates. Specifically, when considering a candidate
during overload resolution this patch makes us shortcut argument
conversion checking upon encountering the first bad conversion
(tentatively marking the candidate as non-strictly viable, though it
could ultimately be unviable) under the assumption that we'll eventually
find a strictly viable candidate anyway (which renders moot the
distinction between non-strictly viable and unviable, since both are
worse than a strictly viable candidate). If this assumption turns out
to be false, we'll fully reconsider the candidate under the defacto
behavior (without the shortcutting) so that all its conversions are
computed.
So in the best case (there's a strictly viable candidate), we avoid
some argument conversions and/or template argument deduction that may
cause a hard error. In the worst case (there's no such candidate), we
have to redundantly consider some candidates twice. (In a previous
version of the patch, to avoid this redundant checking I created a new
"deferred" conversion type that represents a conversion that is yet to
be computed, and instead of reconsidering a candidate I just realized
its deferred conversions. But it doesn't seem this redundancy is a
significant performance issue to justify the added complexity of this
other approach.)
PR c++/101904
gcc/cp/ChangeLog:
* call.c (build_this_conversion): New function, split out from
add_function_candidate.
(add_function_candidate): New parameter shortcut_bad_convs.
Document it. Use build_this_conversion. Stop at the first bad
argument conversion when shortcut_bad_convs is true.
(add_template_candidate_real): New parameter shortcut_bad_convs.
Use build_this_conversion to check the 'this' conversion before
attempting deduction. When the rejection reason code is
rr_bad_arg_conversion, pass -1 instead of 0 as the viable
parameter to add_candidate. Pass 'convs' to add_candidate.
(add_template_candidate): New parameter shortcut_bad_convs.
(add_template_conv_candidate): Pass false as shortcut_bad_convs
to add_template_candidate_real.
(add_candidates): Prefer to shortcut bad conversions during
overload resolution under the assumption that we'll eventually
see a strictly viable candidate. If this assumption turns out
to be false, re-process the non-strictly viable candidates
without shortcutting those bad conversions.
gcc/testsuite/ChangeLog:
* g++.dg/template/conv17.C: New test.
^ permalink raw reply [flat|nested] 9+ messages in thread
* [Bug c++/101904] Wrong result of decltype during instantiation of std::result_of
2021-08-13 20:22 [Bug c++/101904] New: Wrong result of decltype during instantiation of std::result_of officesamurai at gmail dot com
` (5 preceding siblings ...)
2021-09-03 15:34 ` cvs-commit at gcc dot gnu.org
@ 2021-09-13 15:14 ` ppalka at gcc dot gnu.org
2021-09-15 22:42 ` cvs-commit at gcc dot gnu.org
7 siblings, 0 replies; 9+ messages in thread
From: ppalka at gcc dot gnu.org @ 2021-09-13 15:14 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101904
Patrick Palka <ppalka at gcc dot gnu.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
Resolution|INVALID |FIXED
Target Milestone|--- |12.0
--- Comment #7 from Patrick Palka <ppalka at gcc dot gnu.org> ---
Changing the resolution to "fixed" for the record, since after the above commit
we now accept such code (which is permitted but not required by the standard).
^ permalink raw reply [flat|nested] 9+ messages in thread
* [Bug c++/101904] Wrong result of decltype during instantiation of std::result_of
2021-08-13 20:22 [Bug c++/101904] New: Wrong result of decltype during instantiation of std::result_of officesamurai at gmail dot com
` (6 preceding siblings ...)
2021-09-13 15:14 ` ppalka at gcc dot gnu.org
@ 2021-09-15 22:42 ` cvs-commit at gcc dot gnu.org
7 siblings, 0 replies; 9+ messages in thread
From: cvs-commit at gcc dot gnu.org @ 2021-09-15 22:42 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101904
--- Comment #8 from CVS Commits <cvs-commit at gcc dot gnu.org> ---
The master branch has been updated by Patrick Palka <ppalka@gcc.gnu.org>:
https://gcc.gnu.org/g:22806064a67cf30599957c1ffb322aa30e9e57e7
commit r12-3559-g22806064a67cf30599957c1ffb322aa30e9e57e7
Author: Patrick Palka <ppalka@redhat.com>
Date: Wed Sep 15 18:41:21 2021 -0400
c++: shortcut bad convs during overload resolution, part 2 [PR101904]
The r12-3346 change makes us avoid computing excess argument conversions
during overload resolution, but only when it turns out there's a
strictly viable candidate in the overload set. If there's no such
candidate then we still need to compute more conversions than strictly
necessary because subsequent conversions after the first bad conversion
can turn a non-strictly viable candidate into an unviable one, and that
affects the outcome of overload resolution and the behavior of its
callers (because of -fpermissive).
But at least in a SFINAE context, the distinction between a non-strictly
viable and an unviable candidate shouldn't matter all that much since
performing a bad conversion is always an error (even with -fpermissive),
and so forming a call to a non-strictly viable candidate will end up
being a SFINAE error anyway, just like in the unviable case. Hence a
non-strictly viable candidate is effectively unviable (in a SFINAE
context), and we don't really need to distinguish between the two kinds.
We can take advantage of this observation to avoid computing excess
argument conversions even when there's no strictly viable candidate in
the overload set.
This patch implements this idea. We usually detect a SFINAE context by
looking for the absence of the tf_error flag, but that's not specific
enough: we can also get here from build_user_type_conversion with
tf_error cleared, and there the distinction between a non-strictly
viable candidate and an unviable candidate still matters (it determines
whether a user-defined conversion is bad or just doesn't exist). So this
patch sets and checks for the tf_conv flag to detect this situation too,
which avoids regressing conv2.C below.
Unlike the previous change, this one does affect the outcome of overload
resolution, but it should do so only in a way that preserves backwards
compatibility with -fpermissive.
PR c++/101904
gcc/cp/ChangeLog:
* call.c (build_user_type_conversion_1): Add tf_conv to complain.
(add_candidates): When in a SFINAE context, instead of adding a
candidate to bad_fns just mark it unviable.
gcc/testsuite/ChangeLog:
* g++.dg/ext/conv2.C: New test.
* g++.dg/template/conv17.C: Extend test.
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2021-09-15 22:42 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-13 20:22 [Bug c++/101904] New: Wrong result of decltype during instantiation of std::result_of officesamurai at gmail dot com
2021-08-15 6:49 ` [Bug c++/101904] " redi at gcc dot gnu.org
2021-08-15 20:42 ` officesamurai at gmail dot com
2021-08-17 9:57 ` redi at gcc dot gnu.org
2021-08-17 15:32 ` redi at gcc dot gnu.org
2021-08-24 3:58 ` ppalka at gcc dot gnu.org
2021-09-03 15:34 ` cvs-commit at gcc dot gnu.org
2021-09-13 15:14 ` ppalka at gcc dot gnu.org
2021-09-15 22:42 ` cvs-commit at gcc dot gnu.org
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).