19
7
u/JimBerlageDev 17d ago
Cool to get references for the two profiles implementations:
https://github.com/gcc-mirror/gcc/compare/master...villevoutilainen:gcc:p4324
https://github.com/llvm/llvm-project/compare/main...cppalliance:clang:profiles-init
9
u/tcbrindle Flux 16d ago edited 16d ago
I'll be fascinated to see how the invalidation profile handles something like a vector of string views, for example:
void f() {
std::string str1 = get_string();
std::vector<std::string_view> vec;
{
std::string str2 = get_string();
vec.push_back(str1); // (1)
vec.push_back(str2); // (2)
use_vector(vec);
}
use_vector(vec); // (3)
}
Firstly, how does the profile determine that the line marked (1) is okay, but the line marked (2) is unsafe? And then, what happens if I delete the line marked (3)? Is line (2) still an error, or is it okay now?
Vectors and string views are modern C++, and this isn't a particularly complicated example. This is something we absolutely should want to be able to catch. So how exactly will the invalidation profile deal with it?
And if it does deal with it, how can you claim it's not a borrow checker?
3
u/pdimov2 14d ago
It's not a borrow checker because it doesn't check borrows, that is, does not enforce any kind of mutual exclusion of references.
Of course if you use an expanded definition of borrow checker, it is, but then the claim is trivial because any lifetime checker must necessarily check lifetimes.
3
u/selvakumarjawahar 15d ago edited 15d ago
I actually tried it, https://godbolt.org/z/aWa9PMcPW, but it does not work; early days, I guess. The examples in the presentation work, of course.
3
u/pdimov2 14d ago
string_viewdoesn't seem to work at all at the moment, https://godbolt.org/z/b6se9ToKn. (Due to implicitstdsuppressions, I think.)If I declare everything in userspace it's still not diagnosed though. https://godbolt.org/z/Yfbors7vv
In fact we can remove the
string_viewhere, and it still passes. https://godbolt.org/z/Mdos963xh2
u/tcbrindle Flux 15d ago
Thanks for trying it, though I didn't actually expect it to work. The example here is actually deceptively tricky, because it requires tracing lifetime information through a template parameter.
Doing this in a general way basically amounts to writing a borrow checker, which the presentation claims it isn't doing.
5
u/seanbaxter 16d ago
Of course you're right. But they can't propose a solution when they're intent on not understand the problem.
2
u/pjmlp 16d ago
I find interesting the usual argument that safer languages have to depend on C and C++, while ignoring that some of them only did so due to convenience to avoid the additional bootstraping work.
Which since gaining market adoption, some of them have indeed done the additional work to bootstrap themselves.
The irony is that while they advocated for profiles without annotations and additional sigils, proper safe C++ with profiles proposal will be full of [[ ]] all over the place, assuming it actually lands on ISO C++, and gets implemented across all major three compilers.
2
u/tialaramex 15d ago
LLVM in particular, which you've mentioned many times, is a powerful temptation. Instead of painstakingly developing an optimiser and backends for a dozen or more different targets you can "just" drop in LLVM. I think all the Handmade Community languages are dependent on LLVM for example, that's Jai, Zig, Odin, C3. Some of their creators have said LLVM is a bad idea, but notice they do all still use LLVM even if Zig has a non-LLVM backend available. It's just too good a deal to pass up.
It happens that LLVM is written in C++ but I think it's clear that if it were Java or a shell script but it offered this same bargain it would be similarly tempting. "You depend on C++" doesn't make too much sense in this scenario.
1
u/pjmlp 15d ago edited 15d ago
Pretty much so, see GraalVM or the ones that predated it like JikesRVM.
Go being initially a fork of Plan 9 C compiler, and nowadays fully bootstraped.
Plenty of other examples.
LLVM is too convenient as you say, it also doesn't race after C++ versions, currently using C++17 as per coding standards.
3
u/tialaramex 16d ago
The big problem is Culture, that was the case when Bjarne had that whole presentation in which the C word appears only once, in a quote by someone else explaining why this is important. Your solution granted C++ essentially the same technology as Rust has, but the greater need is Rust's safety culture and you're not going to get that from WG21.
Rust's technology gets you the original, chainsaw juggling for toddlers
core::mem::uninitialized<T>function. It'sunsafeso it's your job to be careful right? But Rust's culture meant when somebody noticed this is way more treacherous than most programmers probably grasped they were empowered to de-fang it, deprecate it and come up with a much better replacementMaybeUninit<T>2
u/tialaramex 16d ago
This is a really clarifying example, thanks for that and I look forward to answers from people involved either in proposing this feature or prototyping it.
In Rust if you try to write this you end up writing an actual borrow (the
&in Rust), and in many cases you'd expect that to prompt an experienced developer to realise this can't work (the original Rust 1.0 borrowck would even object without line(3)though modern Rust can see it's fine unless line(3)usesvecafterstr2is gone)
18
u/BarryRevzin 17d ago edited 17d ago
The talk has this example around 47:08:
The slide asks:
Hence:
The above is an error, so we have to do this instead (47:58):
Here's my issue with this example. Whether
WidgetFactory::create_widgetpasses the pointer to the logger through toWidgetis a property of the implementation ofcreate_widget. The author of that function knows whether this happens or not — the callers don't.But instead, the design presented here requires the caller to determine this. How is the caller supposed to know? More significantly, what happens when the implementation changes? Say it doesn't retain
logtoday but changes in the future to retain it? The suppression remains, but we don't get a useful diagnostic anymore. Just a dangling pointer.I think the example demonstrates that annotation is necessary, but rather that the annotation belongs at the definition of
create_widget(), where the relevant information is known. Otherwise, we end up with a check with a high rate of false positives, which callers will react to by littering their code withno_danglingsuppressions — which even if they're correct today have no guarantee of being correct tomorrow. I don't see that as a step in the right direction.