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

Place unions, pointer casts and pointer derefs behind extra feature gates #51990

Merged
merged 9 commits into from
Aug 7, 2018

Conversation

oli-obk
Copy link
Contributor

@oli-obk oli-obk commented Jul 2, 2018

To ensure we don't stabilize these things together with const fn stabilization (or any other stabilization)

This PR moves union field accesses inside const fn behind a feature gate. It was possible without a feature gate before, but since const fn was behind a feature gate we can do this change.

While "dereferencing raw pointers" and "casting raw pointers to usize" were hard errors before this PR, one could work around them by abusing unions:

// deref
union Foo<T> {
    x: &'static T,
    y: *const T,
}
const FOO: u32 = unsafe { *Foo { y: 42 as *const T }.x };

// as usize cast
union Bar<T> {
    x: usize,
    y: *const T,
}
const BAR: usize = unsafe { Bar { y: &1u8 }.x };

r? @eddyb

cc @nikomatsakis

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jul 2, 2018
@rust-highfive

This comment has been minimized.

@stokhos
Copy link

stokhos commented Jul 6, 2018

Ping from triage @eddyb @nikomatsakis this PR needs your review.

if self.mode != Mode::Fn &&
!self.tcx.sess.features_untracked().const_raw_ptr_deref {
emit_feature_err(
&self.tcx.sess.parse_sess, "const_raw_ptr_deref",
Copy link
Member

Choose a reason for hiding this comment

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

Pretty sure you wanted to gate on const_raw_ptr_to_usize_cast here instead.

@eddyb
Copy link
Member

eddyb commented Jul 13, 2018

@nikomatsakis Does this need FCP? This (sneakily) now allows raw pointer dereferences, and casts from pointers to integers, at compile-time, but under a feature gate.

@rust-highfive
Copy link
Collaborator

The job x86_64-gnu-llvm-5.0 of your PR failed on Travis (raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
Check compiletest suite=ui mode=ui compare_mode=nll (x86_64-unknown-linux-gnu -> x86_64-unknown-linux-gnu)
[00:47:11] 
[00:47:11] running 1563 tests
[00:47:14] ..................................................................................................i.
[00:47:18] ......................................................F.........i...................................
[00:47:23] ....................................................................................................
[00:47:25] ....................................................................................................
[00:47:27] ....................................................................................................
[00:47:30] ....................................................................................................
---
[00:47:58] ---- [ui (nll)] ui/const-eval/union_promotion.rs stdout ----
[00:47:58] 
[00:47:58] error: ui test compiled successfully!
[00:47:58] status: exit code: 0
[00:47:58] command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/const-eval/union_promotion.rs" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "-Zui-testing" "-C" "prefer-dynamic" "-o" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/const-eval/union_promotion.nll/a" "-Zborrowck=mir" "-Ztwo-phase-borrows" "-Crpath" "-O" "-Zunstable-options" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/const-eval/union_promotion.nll/auxiliary" "-A" "unused"
[00:47:58] ------------------------------------------
[00:47:58] 
[00:47:58] ------------------------------------------
[00:47:58] stderr:
---
[00:47:58] 
[00:47:58] thread 'main' panicked at 'Some tests failed', tools/compiletest/src/main.rs:498:22
[00:47:58] 
[00:47:58] 
[00:47:58] command did not execute successfully: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-tools-bin/compiletest" "--compile-lib-path" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/lib" "--run-lib-path" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/x86_64-unknown-linux-gnu/lib" "--rustc-path" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "--src-base" "/checkout/src/test/ui" "--build-base" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui" "--stage-id" "stage2-x86_64-unknown-linux-gnu" "--mode" "ui" "--target" "x86_64-unknown-linux-gnu" "--host" "x86_64-unknown-linux-gnu" "--llvm-filecheck" "/usr/lib/llvm-5.0/bin/FileCheck" "--host-rustcflags" "-Crpath -O -Zunstable-options " "--target-rustcflags" "-Crpath -O -Zunstable-options  -Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "--docck-python" "/usr/bin/python2.7" "--lldb-python" "/usr/bin/python2.7" "--gdb" "/usr/bin/gdb" "--quiet" "--llvm-version" "5.0.0\n" "--system-llvm" "--cc" "" "--cxx" "" "--cflags" "" "--llvm-components" "" "--llvm-cxxflags" "" "--adb-path" "adb" "--adb-test-dir" "/data/tmp/work" "--android-cross-path" "" "--color" "always" "--compare-mode" "nll"
[00:47:58] 
[00:47:58] 
[00:47:58] failed to run: /checkout/obj/build/bootstrap/debug/bootstrap test
[00:47:58] Build completed unsuccessfully in 0:02:15
[00:47:58] Build completed unsuccessfully in 0:02:15
[00:47:59] make: *** [check] Error 1
[00:47:59] Makefile:58: recipe for target 'check' failed

The command "stamp sh -x -c "$RUN_SCRIPT"" exited with 2.
travis_time:start:2ea79884
$ date && (curl -fs --head https://google.com | grep ^Date: | sed 's/Date: //g' || true)

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @TimNN. (Feature Requests)

@bors
Copy link
Contributor

bors commented Jul 17, 2018

☔ The latest upstream changes (presumably #52409) made this pull request unmergeable. Please resolve the merge conflicts.

@stokhos
Copy link

stokhos commented Jul 21, 2018

Ping from triage! @nikomatsakis this PR needs your review

@TimNN
Copy link
Contributor

TimNN commented Jul 24, 2018

Ping from triage @nikomatsakis / @rust-lang/compiler: This PR requires your input.

@nikomatsakis
Copy link
Contributor

r? @nikomatsakis

@rust-highfive rust-highfive assigned nikomatsakis and unassigned eddyb Jul 26, 2018
@nikomatsakis
Copy link
Contributor

@eddyb I don't think this requires FCP, but I do think we have to get started on writing a spec and things (which I think @oli-obk and @RalfJung are both trying to make progress on)

@RalfJung
Copy link
Member

There are other operations on raw pointers we have to be careful about as well: Comparison (whether it is == or <). Shouldn't they be treated similar?

@rust-highfive
Copy link
Collaborator

The job x86_64-gnu-llvm-5.0 of your PR failed on Travis (raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
travis_time:start:tidy
tidy check
[00:03:36] * 550 error codes
[00:03:36] * highest error code: E0710
[00:03:36] tidy error: Found 1 features without a gate test.
[00:03:36] Expected a gate test for the feature 'const_compare_raw_pointers'.
[00:03:36] Hint: create a failing test file named 'feature-gate-const_compare_raw_pointers.rs'
[00:03:36]       in the 'ui' test suite, with its failures due to
[00:03:36]       missing usage of #![feature(const_compare_raw_pointers)].
[00:03:36] Hint: If you already have such a test and don't want to rename it,
[00:03:36]       you can also add a // gate-test-const_compare_raw_pointers line to the test file.
[00:03:37] some tidy checks failed
[00:03:37] 
[00:03:37] 
[00:03:37] command did not execute successfully: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-tools-bin/tidy" "/checkout/src" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "--no-vendor" "--quiet"
[00:03:37] 
[00:03:37] 
[00:03:37] failed to run: /checkout/obj/build/bootstrap/debug/bootstrap test src/tools/tidy
[00:03:37] Build completed unsuccessfully in 0:00:47
[00:03:37] Build completed unsuccessfully in 0:00:47
[00:03:37] Makefile:79: recipe for target 'tidy' failed
[00:03:37] make: *** [tidy] Error 1

The command "stamp sh -x -c "$RUN_SCRIPT"" exited with 2.
travis_time:start:04f5daf4
$ date && (curl -fs --head https://google.com | grep ^Date: | sed 's/Date: //g' || true)
---
travis_time:end:2bc652c4:start=1533288423813682659,finish=1533288423819625206,duration=5942547
travis_fold:end:after_failure.3
travis_fold:start:after_failure.4
travis_time:start:05e743e0
$ ln -s . checkout && for CORE in obj/cores/core.*; do EXE=$(echo $CORE | sed 's|obj/cores/core\.[0-9]*\.!checkout!\(.*\)|\1|;y|!|/|'); if [ -f "$EXE" ]; then printf travis_fold":start:crashlog\n\033[31;1m%s\033[0m\n" "$CORE"; gdb -q -c "$CORE" "$EXE" -iex 'set auto-load off' -iex 'dir src/' -iex 'set sysroot .' -ex bt -ex q; echo travis_fold":"end:crashlog; fi; done || true
travis_fold:end:after_failure.4
travis_fold:start:after_failure.5
travis_time:start:18eccf54
travis_time:start:18eccf54
$ cat ./obj/build/x86_64-unknown-linux-gnu/native/asan/build/lib/asan/clang_rt.asan-dynamic-i386.vers || true
cat: ./obj/build/x86_64-unknown-linux-gnu/native/asan/build/lib/asan/clang_rt.asan-dynamic-i386.vers: No such file or directory
travis_fold:end:after_failure.5
travis_fold:start:after_failure.6
travis_time:start:014912a4
$ dmesg | grep -i kill

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @TimNN. (Feature Requests)

@oli-obk
Copy link
Contributor Author

oli-obk commented Aug 3, 2018

There are other operations on raw pointers we have to be careful about as well: Comparison (whether it is == or <). Shouldn't they be treated similar?

done

@RalfJung
Copy link
Member

RalfJung commented Aug 3, 2018

What's the difference between self.add(Qualif::NOT_CONST); and this.non_const()?

@rust-highfive
Copy link
Collaborator

The job x86_64-gnu-llvm-5.0 of your PR failed on Travis (raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.

[00:03:54] travis_fold:start:tidy
travis_time:start:tidy
tidy check
[00:03:54] tidy error: /checkout/src/test/ui/const-eval/const_raw_ptr_ops.rs: missing trailing newline
[00:03:54] tidy error: /checkout/src/test/ui/const-eval/promoted_raw_ptr_ops.rs: missing trailing newline
[00:03:55] some tidy checks failed
[00:03:55] 
[00:03:55] 
[00:03:55] command did not execute successfully: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-tools-bin/tidy" "/checkout/src" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "--no-vendor" "--quiet"
[00:03:55] 
[00:03:55] 
[00:03:55] failed to run: /checkout/obj/build/bootstrap/debug/bootstrap test src/tools/tidy
[00:03:55] Build completed unsuccessfully in 0:00:55
[00:03:55] Build completed unsuccessfully in 0:00:55
[00:03:55] Makefile:79: recipe for target 'tidy' failed
[00:03:55] make: *** [tidy] Error 1

The command "stamp sh -x -c "$RUN_SCRIPT"" exited with 2.
travis_time:start:05c3eda0
$ date && (curl -fs --head https://google.com | grep ^Date: | sed 's/Date: //g' || true)
---
travis_time:end:1cbcba00:start=1533296000539664161,finish=1533296000549270877,duration=9606716
travis_fold:end:after_failure.3
travis_fold:start:after_failure.4
travis_time:start:11f4d6f2
$ ln -s . checkout && for CORE in obj/cores/core.*; do EXE=$(echo $CORE | sed 's|obj/cores/core\.[0-9]*\.!checkout!\(.*\)|\1|;y|!|/|'); if [ -f "$EXE" ]; then printf travis_fold":start:crashlog\n\033[31;1m%s\033[0m\n" "$CORE"; gdb -q -c "$CORE" "$EXE" -iex 'set auto-load off' -iex 'dir src/' -iex 'set sysroot .' -ex bt -ex q; echo travis_fold":"end:crashlog; fi; done || true
travis_fold:end:after_failure.4
travis_fold:start:after_failure.5
travis_time:start:2c9c0ae5
travis_time:start:2c9c0ae5
$ cat ./obj/build/x86_64-unknown-linux-gnu/native/asan/build/lib/asan/clang_rt.asan-dynamic-i386.vers || true
cat: ./obj/build/x86_64-unknown-linux-gnu/native/asan/build/lib/asan/clang_rt.asan-dynamic-i386.vers: No such file or directory
travis_fold:end:after_failure.5
travis_fold:start:after_failure.6
travis_time:start:0f04735b
$ dmesg | grep -i kill

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @TimNN. (Feature Requests)

@oli-obk
Copy link
Contributor Author

oli-obk commented Aug 3, 2018

the not_const method produces an additional error message per invocation

@RalfJung
Copy link
Member

RalfJung commented Aug 3, 2018

Okay, let me ask differently: Most of the code does

if let Mode::Fn = this.mode {
    this.add(Qualif::NOT_CONST);
} else if /* feature is not enabled */ {
  // complain
}

Just unions do something that at least looks completely different: They call not_const(), and they do not complain if the mode is not Mode::ConstFn. Why? There's probably a good reason, but that reason certainly deserves a comment in the code. :)

@oli-obk
Copy link
Contributor Author

oli-obk commented Aug 3, 2018

calling not_const after checking for Mode::Fn is exactly the same as adding the NOT_CONST qualif. In any other mode not_const produces an error. If I understand it correctly #52518 will clean this all up nicely anyway

@RalfJung
Copy link
Member

RalfJung commented Aug 3, 2018

calling not_const after checking for Mode::Fn is exactly the same as adding the NOT_CONST qualif. In any other mode not_const produces an error.

Okay.

And union field accesses in statics and consts are deliberately allowed for backwards compatibility? This is code that asked to be const and hence it's fine if miri shows strange errors?

@oli-obk
Copy link
Contributor Author

oli-obk commented Aug 3, 2018

And union field accesses in statics and consts are deliberately allowed for backwards compatibility? This is code that asked to be const and hence it's fine if miri shows strange errors?

yes, this has been stable for a year and has been erroring with unhelpful errors before miri (field not found even though it obviously was there, just not the one that was assigned to) and with potentially strange errors after miri (if the transmute was unconst).

@nikomatsakis
Copy link
Contributor

r=me but needs rebase

@oli-obk
Copy link
Contributor Author

oli-obk commented Aug 7, 2018

@bors r=nikomatsakis

@bors
Copy link
Contributor

bors commented Aug 7, 2018

📌 Commit 4b731a9 has been approved by nikomatsakis

@bors bors 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-review Status: Awaiting review from the assignee but also interested parties. labels Aug 7, 2018
@bors
Copy link
Contributor

bors commented Aug 7, 2018

⌛ Testing commit 4b731a9 with merge 39e9516...

bors added a commit that referenced this pull request Aug 7, 2018
Place unions, pointer casts and pointer derefs behind extra feature gates

To ensure we don't stabilize these things together with const fn stabilization (or any other stabilization)

This PR moves union field accesses inside `const fn` behind a feature gate. It was possible without a feature gate before, but since `const fn` was behind a feature gate we can do this change.

While "dereferencing raw pointers" and "casting raw pointers to usize" were hard errors before this PR, one could work around them by abusing unions:

```rust
// deref
union Foo<T> {
    x: &'static T,
    y: *const T,
}
const FOO: u32 = unsafe { *Foo { y: 42 as *const T }.x };

// as usize cast
union Bar<T> {
    x: usize,
    y: *const T,
}
const BAR: usize = unsafe { Bar { y: &1u8 }.x };
```

r? @eddyb

cc @nikomatsakis
@bors
Copy link
Contributor

bors commented Aug 7, 2018

☀️ Test successful - status-appveyor, status-travis
Approved by: nikomatsakis
Pushing 39e9516 to master...

@bors bors merged commit 4b731a9 into rust-lang:master Aug 7, 2018
this.add(Qualif::NOT_CONST);
} else {
let base_ty = proj.base.ty(this.mir, this.tcx).to_ty(this.tcx);
if let ty::TyRawPtr(_) = base_ty.sty {
Copy link
Member

Choose a reason for hiding this comment

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

I think this change is wrong. All derefs are NOT_CONST, because we can never prove anything strong enough about the pointer/reference. this.add(Qualif::NOT_CONST); was not within if let ty::TyRawPtr(_) = base_ty.sty {.

The practical effects are that this compiles on nightly:

#![feature(nll)]
const FOO: Option<&[[u8; 3]]> = Some(&[*b"foo"]);

Thankfully, NLL is still unstable, so we didn't regress in any stable-visible way.

Copy link
Member

Choose a reason for hiding this comment

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

All derefs are NOT_CONST, because we can never prove anything strong enough about the pointer/reference.

How that, safe references should be fine?

Copy link
Member

Choose a reason for hiding this comment

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

Oh your comment in #54224 indicates this is about promotion. Then never mind, I anyway have no idea what happens there.^^

Copy link
Member

Choose a reason for hiding this comment

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

The type is safe, but the value isn't guaranteed to be valid / not point to a static.

Copy link
Member

Choose a reason for hiding this comment

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

I can't parse the end of your sentence, do you mean "isn't guaranteed to point to a static" or "isn't guaranteed to NOT point to a static"?

Copy link
Member

Choose a reason for hiding this comment

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

"isn't guaranteed to (be valid | not point to a static)"
(as in, pointing to a static is as invalid as a random unsafe pointer, for promotion - since the value may be different at runtime)

Copy link
Member

Choose a reason for hiding this comment

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

Uh, what? I would have thoughts statics are the least problematic to point at in a promoted (aka another static)...?

Copy link
Member

Choose a reason for hiding this comment

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

Maybe in a constant, yeah, but in the general case, a static could've changed at runtime.

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.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants