$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
Subject: Re: [boost] [outcome] To variant, or not to variant?
From: Peter Dimov (lists_at_[hidden])
Date: 2017-06-03 09:42:39
Vicente J. Botet Escriba wrote:
> Peter, I not be against an implementation that returns nullptr of
> operator-> as far as this is not documented and something the user could
> use.
> If returning a nulptr is the best thing that we can do today in order to
> help the current tools to catch UB, why not.
> I don't agree on documenting it, because this could make some user code
> more complex.
> When you have a narrow contract you know that the check must be done
> before. If you document that it the user can be tempted to check it.
The expression `r->x` still has a narrow contract under my formulation. You
(and the static analyzer) still know that a check needs to be done. It's
just specified differently because the real world consequences of this
specification are more in line with the semantics I want to express.
> Well operator-> is particular in some way as the user doesn't use to use
> it as x.operator->().
Yes, `r.operator->()` is now defined, which some consider desirable.
Presumably, if one writes `auto* p = r.operator->();`, one is aware of what
one's doing. I wouldn't presume that this code is a logic error without a
check, and neither should a static analyzer.
> Consider for a moment that some compiler manage better UB when we do a
> check and assert for unreachable code (as other are suggesting). Requiring
> a nullptr as result will forbid this implementation, isn't it?
No, it doesn't. This formulation just lifts the undefined behavior in `r->x`
from the library into user code, and what happens there depends on the
compiler. g++ takes care to trap on null pointer access, clang++ optimizes
out the checks under the assumption that null pointer accesses don't occur.
The balance here is hard to strike, because there are security implications
of just allowing `p->m = ...` to write over the error; at the same time,
there's an argument to be made to optimize correct programs more at the
expense of incorrect programs. The main feature of my formulation here is
that `r->x` and `p->x` (where p is a raw pointer) elicit a consistent
response from the compiler when they invoke UB, and are therefore covered by
the same optimization decisions or command line switches.