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

arbitrary_self_types: add support for raw pointer self types #46664

Merged
merged 14 commits into from
Dec 19, 2017

Conversation

mikeyhew
Copy link
Contributor

This adds support for raw pointer self types, under the arbitrary_self_types feature flag. Types like self: *const Self, self: *const Rc<Self>, self: Rc<*const Self are all supported. Object safety checks are updated to allowself: *const Self and self: *mut Self.

This PR does not add support for *const self and *mut self syntax. That can be added in a later PR once this code is reviewed and merged.

#44874

r? @arielb1

@kennytm kennytm added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Dec 11, 2017
let t = self.structurally_resolved_type(span, final_ty);
assert_eq!(t, self.tcx.types.err);
return None
// don't report a type error if we dereferenced a raw pointer,
Copy link
Contributor

@arielb1 arielb1 Dec 12, 2017

Choose a reason for hiding this comment

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

Is that really a problem in practice?

If then, I think we might want a warning cycle here. This looks like a sort of expected inference breakage, so it should remain an error.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It broke something in libstd:

let mut data = ptr::null();

Here's a minimal reproduction:

fn main() {
    let data = std::ptr::null();
    let _ = &data as *const *const ();
    if data.is_null() {}
}

Copy link
Contributor

Choose a reason for hiding this comment

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

I get that. I think we should probably make this a future-compat warning, or an error with the arbitrary_self_types feature flag set.

@@ -8,11 +8,17 @@
// option. This file may not be copied, modified, or distributed
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you also add a test for "complex" cases - i.e. Rc<*const Self> & *const Rc<Self>?

@arielb1
Copy link
Contributor

arielb1 commented Dec 12, 2017

r=me with a test for complex cases added

I documented the "inference suppression" thing at the now-tracking-issue, but we need to look at it.

@arielb1 arielb1 added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Dec 12, 2017
@arielb1
Copy link
Contributor

arielb1 commented Dec 12, 2017

Actually, allowing for object-safe raw pointers is a bit controversial, because it means that fat raw pointers have some semantics.

aka:

trait Foo {
    fn bar(self: *const Self);
}

fn main() {
    let foo: *const Foo = mem::transmute([0usize, 0usize]);
    foo.bar(); // this is UB
}

I think that fat raw pointers already have some semantics - you can call size_of_val on them - but I'll rather not unilaterally specify more semantics for them.

@rfcbot fcp start

@kennytm
Copy link
Member

kennytm commented Dec 13, 2017

@arielb1 you mean @rfcbot fcp merge?

BTW since transmute is unsafe and ptr::null is not defined for DSTs I don’t think this particular code sample is a big issue.

@mikeyhew
Copy link
Contributor Author

@arielb1 size_of_val currently only takes a reference, not a raw pointer. I started a discussion in the rfcs repo about changing it to take *const T.

as @kennytm pointed out, the example above requires unsafe code to cause undefined behaviour. Using transmute to create a trait object is especially unsafe, and this is mentioned in the documentation of raw::TraitObject.

This PR in its current state (with object-safe raw pointer methods) exposes the following invariants about the language implementation:

  1. trait object pointers will always be fat pointers, with the vtable(s) stored in the pointer, and
  2. the vtable(s) will always be valid.

It is pretty much impossible for (1) not to be true, due to the nature of traits, and how any type can implement arbitrary traits. For a trait object to be a thin pointer, the vtable would have to be stored with the data, and that means every i32 that you cast to a trait object would have to be an extra word bigger to store the vtable to that trait. Did I say "pretty much" impossible? No, it's definitely impossible, because what if you cast a pointer to the same i32 field to two different trait objects?

(2) is maybe a bit more controversial, but this was discussed in #44932 because the assumption in making ptr::null(p) be equivalent to (p as *const ()).is_null() was that DST pointers would always have valid metadata. @dtolnay was the only person in that discussion to disagree, and he has since changed his mind and added that behaviour in a new PR #46094

@arielb1
Copy link
Contributor

arielb1 commented Dec 13, 2017

r=me with the type error made into a future compat warning + a hard error with the feature gate enabled.

@kennytm kennytm added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Dec 13, 2017
@mikeyhew
Copy link
Contributor Author

@arielb1 should be good to go

@kennytm
Copy link
Member

kennytm commented Dec 14, 2017

@mikeyhew CI is failing, ui/inference-variable-behind-raw-pointer.rs did not error out.

[00:53:29] ---- [ui] ui/inference-variable-behind-raw-pointer.rs stdout ----
[00:53:29] 	
[00:53:29] error: ui test compiled successfully!
[00:53:29] status: exit code: 0
[00:53:29] command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/inference-variable-behind-raw-pointer.rs" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "-C" "prefer-dynamic" "-o" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/inference-variable-behind-raw-pointer.stage2-x86_64-unknown-linux-gnu" "-Crpath" "-O" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/inference-variable-behind-raw-pointer.stage2-x86_64-unknown-linux-gnu.aux" "-A" "unused"
[00:53:29] stdout:
[00:53:29] ------------------------------------------
[00:53:29] 
[00:53:29] ------------------------------------------
[00:53:29] stderr:
[00:53:29] ------------------------------------------
[00:53:29] {"message":"the type of this value must be known in this context","code":{"code":"E0619","explanation":"\nThe type-checker needed to know the type of an expression, but that type had not\nyet been inferred.\n\nErroneous code example:\n\n```compile_fail,E0619\nlet mut x = vec![];\nmatch x.pop() {\n    Some(v) => {\n        // Here, the type of `v` is not (yet) known, so we\n        // cannot resolve this method call:\n        v.to_uppercase(); // error: the type of this value must be known in\n                          //        this context\n    }\n    None => {}\n}\n```\n\nType inference typically proceeds from the top of the function to the bottom,\nfiguring out types as it goes. In some cases -- notably method calls and\noverloadable operators like `*` -- the type checker may not have enough\ninformation *yet* to make progress. This can be true even if the rest of the\nfunction provides enough context (because the type-checker hasn't looked that\nfar ahead yet). In this case, type annotations can be used to help it along.\n\nTo fix this error, just specify the type of the variable. Example:\n\n```\nlet mut x: Vec<String> = vec![]; // We precise the type of the vec elements.\nmatch x.pop() {\n    Some(v) => {\n        v.to_uppercase(); // Since rustc now knows the type of the vec elements,\n                          // we can use `v`'s methods.\n    }\n    None => {}\n}\n```\n"},"level":"warning","spans":[{"file_name":"/checkout/src/test/ui/inference-variable-behind-raw-pointer.rs","byte_start":563,"byte_end":570,"line_start":14,"line_end":14,"column_start":13,"column_end":20,"is_primary":true,"text":[{"text":"    if data.is_null() {}","highlight_start":13,"highlight_end":20}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"this will be made into a hard error in a future version of the compiler","code":null,"level":"note","spans":[],"children":[],"rendered":null}],"rendered":"warning[E0619]: the type of this value must be known in this context\n  --> /checkout/src/test/ui/inference-variable-behind-raw-pointer.rs:14:13\n   |\n14 |     if data.is_null() {}\n   |             ^^^^^^^\n   |\n   = note: this will be made into a hard error in a future version of the compiler\n\n"}
[00:53:29] 
[00:53:29] ------------------------------------------
[00:53:29] 
[00:53:29] thread '[ui] ui/inference-variable-behind-raw-pointer.rs' panicked at 'explicit panic', /checkout/src/tools/compiletest/src/runtest.rs:2774:8
[00:53:29] note: Run with `RUST_BACKTRACE=1` for a backtrace.
[00:53:29] 
[00:53:29] 
[00:53:29] failures:
[00:53:29]     [ui] ui/inference-variable-behind-raw-pointer.rs
[00:53:29] 
[00:53:29] test result: FAILED. 666 passed; 1 failed; 1 ignored; 0 measured; 0 filtered out

@arielb1
Copy link
Contributor

arielb1 commented Dec 14, 2017

@mikeyhew

You should use a future-compat warning so you can use #![deny(warning_name)] to test it.

This does feel a little heavyweight, but I think the alternatives are worse. I'll ask @nikomatsakis about it.

@mikeyhew
Copy link
Contributor Author

@kennytm so the error is that it compiles successfully? How do I tell the ui test suite that it's supposed to compile? Funnily enough, it passes on my machine, were ui tests changed since I last rebased off of master on Dec 10?

@arielb1
Copy link
Contributor

arielb1 commented Dec 15, 2017

@mikeyhew

We did change UI tests so that they need to fail to compile unless you add this line to the start of the test (look for it in existing tests, e.g. https://github.com/rust-lang/rust/blob/master/src/test/ui/hello_world/main.rs):

// must-compile-successfully

@mikeyhew
Copy link
Contributor Author

mikeyhew commented Dec 15, 2017

I found an old RFC PR that suggests allowing traits to opt into having the vtable stored with the data: rust-lang/rfcs#250. This goes against (1) in my comment above. However, since that feature would be opt-in for specific traits, it would be easy to make raw pointer methods non-object-safe for those traits only, either by checking for #[repr(internal_vtable)] or by introducing a new trait, e.g. FatDynSized and requiring it

@mikeyhew
Copy link
Contributor Author

@kennytm you're confused by my comment?

@arielb1
Copy link
Contributor

arielb1 commented Dec 15, 2017

Looks like you need to update a test

[01:02:25]  error[E0038]: the trait `Foo` cannot be made into an object
[01:02:25]    --> $DIR/arbitrary-self-types-not-object-safe.rs:40:33
[01:02:25]     |
[01:02:25]  40 |     let x = Box::new(5usize) as Box<Foo>;
[01:02:25]     |                                 ^^^^^^^^ the trait `Foo` cannot be made into an object
[01:02:25]     |
[01:02:25] -   = note: method `foo` has a non-standard `self` type. Only `&self`, `&mut self`, and `Box<Self>` are currently supported for trait objects
[01:02:25] +   = note: method `foo` has a non-standard `self` type
[01:02:25]  
[01:02:25]  error[E0038]: the trait `Foo` cannot be made into an object
[01:02:25]    --> $DIR/arbitrary-self-types-not-object-safe.rs:40:13
[01:02:25]     |
[01:02:25]  40 |     let x = Box::new(5usize) as Box<Foo>;
[01:02:25]     |             ^^^^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object
[01:02:25]     |
[01:02:25] -   = note: method `foo` has a non-standard `self` type. Only `&self`, `&mut self`, and `Box<Self>` are currently supported for trait objects
[01:02:25] +   = note: method `foo` has a non-standard `self` type
[01:02:25]     = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<std::boxed::Box<Foo>>` for `std::boxed::Box<usize>`
[01:02:25]  
[01:02:25]  error: aborting due to 2 previous errors
[01:02:25]  
[01:02:25]  
[01:02:25] failures:
[01:02:25]     [ui] ui/arbitrary-self-types-not-object-safe.rs

@mikeyhew
Copy link
Contributor Author

looks like I need to rebase, because that test is under compile-fail for me

@arielb1
Copy link
Contributor

arielb1 commented Dec 18, 2017

@bors r+

@bors
Copy link
Contributor

bors commented Dec 18, 2017

📌 Commit 5c656f0 has been approved by arielb1

@kennytm kennytm added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Dec 18, 2017
@bors
Copy link
Contributor

bors commented Dec 19, 2017

⌛ Testing commit 5c656f0 with merge a9f047c...

bors added a commit that referenced this pull request Dec 19, 2017
arbitrary_self_types: add support for raw pointer `self` types

This adds support for raw pointer `self` types, under the `arbitrary_self_types` feature flag. Types like `self: *const Self`, `self: *const Rc<Self>`, `self: Rc<*const Self` are all supported. Object safety checks are updated to allow`self: *const Self` and `self: *mut Self`.

This PR does not add support for `*const self` and `*mut self` syntax. That can be added in a later PR once this code is reviewed and merged.

#44874

r? @arielb1
@bors
Copy link
Contributor

bors commented Dec 19, 2017

☀️ Test successful - status-appveyor, status-travis
Approved by: arielb1
Pushing a9f047c to master...

@bors bors merged commit 5c656f0 into rust-lang:master Dec 19, 2017
bors added a commit that referenced this pull request Dec 25, 2017
Convert warning about `*const _` to a future-compat lint

#46664 was merged before I could convert the soft warning about method lookup on `*const _` into a future-compatibility lint. This PR makes that change.

fixes #46837
tracking issue for the future-compatibility lint: #46906

r? @arielb1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants