This is a little different, IMO. This is comparing a join utility function/method, rather than an instance method. Personally, join behaves exactly as I expected it to, probably because I’m most familiar with ruby’s Pathname class:
require 'pathname'
p = Pathname.new("some") => #<Pathname:some>
p.join("/path", "yknow") => #<Pathname:/path/yknow>
For me, operating on an existing PathBuf, I expect join to give me the equivalent to changing around directories in a filesystem, and rely on this behavior to allow a user to specify a path which is either absolute or relative to some other (often non-cwd) directory. This is the relative-to-Cargo.toml behavior.
On the other hand, a hypothetical (variadic) PathBuf::join("some", "/path", "yknow") I’d expect to mirror the ruby/node utility functions.
Just for completeness, there’s also this:
println!("{:?}", ["some", "/path", "yknow"].iter().collect::<PathBuf>());
=> /path/yknow
I do agree that join as a name is, at best, vague. Also, I think referring to these as “non-destructive” is a little unclear – I initially thought you meant the operations returned a new PathBuf, rather than altering the existing buffer.
And I guess we could bikeshed these until the end of time, but the difference between append, push, concat and join feels semantically vague. Thanks to ruby and javascript, I’ll never really know what to expect from concat. Ruby’s concat mutates the receiver in place, js returns a newly allocated object. Wheeeee. 
Finally, I think relying on the current working directory for anything related to generate relative paths is not a good idea. (OTOH, I don’t totally understand the reasoning around needing to get the CWD, so I might be missing something.) The relative_path_from method in ruby’s Pathname class has worked well for my use-cases.