Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stop generating an intermediate deref when taking references to statics #76982

Closed
wants to merge 1 commit into from

Conversation

oli-obk
Copy link
Contributor

@oli-obk oli-obk commented Sep 20, 2020

r? @RalfJung

fixes #74840

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Sep 20, 2020
ty::RawPtr(..) => "raw ",
_ => bug!("Rvalue::ThreadLocalRef types can only be pointer or reference"),
};
write!(fmt, "&{}/*tls*/ {}{}", raw, muta, tcx.def_path_str(did))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is TLS between "raw" and "mut"?

let muta = ty.builtin_deref(true).unwrap().mutbl.prefix_str();
let raw = match ty.kind() {
ty::Ref(..) => "",
ty::RawPtr(..) => "raw ",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you are matching anyway, the same match could also extract the mutability... do you think taht would make the code cleaner?

let res = cx.typeck_results().qpath_res(qpath, arg.hir_id);
if let Res::Def(DefKind::Static, id) = res {
let mut tm = cx.tcx.static_ptr_ty(id).builtin_deref(true).unwrap();
tm.mutbl = mutability;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like shoehorning the existing static_ptr_ty helper into something else. Is that helper still used elsewhere, given the new shape of things?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, it's still used further up. I didn't want to repeat its code, but I could split out the part that obtains the static's type into a separate function

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In particular, that function contains some subtle logic if I recall correctly (for using raw ptrs vs references), and now we overlay our own logic on top of this here... given how critical this code is, I'd prefer that to be cleaner, even if that makes the code longer.

Also it would be good to have some comments explaining why all of this here crucially has to be exactly the way it is.

Copy link
Member

@RalfJung RalfJung Sep 21, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, it's still used further up.

Ah, I just saw that. But that further up should now not be reachable any more for refs-to-static, right, just for when it is used as a value? If so, please add a comment explaining that. Also, doesn't that mean we can always use a shared reference, as we always just read? Well and I guess a raw pointer for unsafe-to-read things to make sure we do not sidestep the unsafety checker.

I feel like all the subtle logic that determines the type of the reference we use for reads and for address-of should be in one place.

fn main() {
bar(unsafe { core::ptr::raw_const!(FOO) });
bar(unsafe { &raw const FOO });
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you also somewhere (hopefully there is a good existing test file?) add a test for the thread-local case? After all this PR also changes thread-local static ptrs quite a bit, would be good to have that covered as well.

@@ -0,0 +1,21 @@
#![feature(never_type)]
#![feature(raw_ref_macros)]
#![feature(raw_ref_op)]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add deny(unreachable_code) (with a comment) to ensure even more that this test fails without the PR? The MIR output is auto-blessable so there is some risk that it'll just get blessed in the future if this ever regresses...

def_id: id,
}
};
let kind = convert_static_ref(cx, id, ty);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"kind" is a really confusing variable name here, this is an expression after all.

@oli-obk
Copy link
Contributor Author

oli-obk commented Sep 21, 2020

So... none of these changes actually affect the test to make it pass...

The root problem is much earlier. Typeck decides that these expressions are unreachable because it sees FOO being accessed and just assumes things are unreachable from there on. These checks happen in

pub(super) fn check_expr_with_expectation(
and
// Any expression that produces a value of type `!` must have diverged
if ty.is_never() {
self.diverges.set(self.diverges.get() | Diverges::always(expr.span));
}
is likely what's causing this entire issue.

@oli-obk
Copy link
Contributor Author

oli-obk commented Sep 21, 2020

I don't really want to keep slapping more hacks on top of this function... Can we just add a future incompat error for extern statics that are of uninhabited type? I don't see any way to use them safely and they seem fairly useless if the only thing you can soundly do with them is to take a raw pointer to them.

@RalfJung
Copy link
Member

The root problem is much earlier. Typeck decides that these expressions are unreachable because it sees FOO being accessed and just assumes things are unreachable from there on.

Somehow my understanding was that this is a regression introduced by the move away from statics-as-places towards statics-as-ptrs... but that does not even seem to be the case, these uninhabited extern statics never worked, did they?

I agree it is not worth adding a typeck hack just to silence this warning.

Can we just add a future incompat error for extern statics that are of uninhabited type? I don't see any way to use them safely and they seem fairly useless if the only thing you can soundly do with them is to take a raw pointer to them.

Sounds fine to me.

@oli-obk
Copy link
Contributor Author

oli-obk commented Sep 21, 2020

these uninhabited extern statics never worked, did they?

No

just to silence this warning.

It's not just about the warning. Typeck causes this to become UB (the Unreachable terminator still exists in the new mir-opt test I added)

@oli-obk oli-obk closed this Sep 21, 2020
@oli-obk oli-obk deleted the mir_static_ref branch September 21, 2020 11:28
@RalfJung
Copy link
Member

RalfJung commented Sep 21, 2020

the Unreachable terminator still exists in the new mir-opt test I added

Oh, dang.

(moving discussion back to the issue)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Creating a raw reference/pointer to an extern never value claims following code is unreachable
3 participants