{"action":"created","issue":{"url":"https://api.github.com/repos/rust-lang/rust/issues/11445","repository_url":"https://api.github.com/repos/rust-lang/rust","labels_url":"https://api.github.com/repos/rust-lang/rust/issues/11445/labels{/name}","comments_url":"https://api.github.com/repos/rust-lang/rust/issues/11445/comments","events_url":"https://api.github.com/repos/rust-lang/rust/issues/11445/events","html_url":"https://github.com/rust-lang/rust/issues/11445","id":25379462,"number":11445,"title":"Avoid placing immutable lvalues in allocas and zeroing them to cancel cleanup.","user":{"login":"eddyb","id":77424,"avatar_url":"https://avatars.githubusercontent.com/u/77424?v=3","gravatar_id":"","url":"https://api.github.com/users/eddyb","html_url":"https://github.com/eddyb","followers_url":"https://api.github.com/users/eddyb/followers","following_url":"https://api.github.com/users/eddyb/following{/other_user}","gists_url":"https://api.github.com/users/eddyb/gists{/gist_id}","starred_url":"https://api.github.com/users/eddyb/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/eddyb/subscriptions","organizations_url":"https://api.github.com/users/eddyb/orgs","repos_url":"https://api.github.com/users/eddyb/repos","events_url":"https://api.github.com/users/eddyb/events{/privacy}","received_events_url":"https://api.github.com/users/eddyb/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/rust-lang/rust/labels/A-codegen","name":"A-codegen","color":"d7e102"}],"state":"closed","locked":false,"assignee":null,"milestone":null,"comments":8,"created_at":"2014-01-10T07:31:36Z","updated_at":"2016-02-02T18:20:52Z","closed_at":"2016-02-02T18:20:52Z","body":"This is the current LLVM IR generated at `--opt-level=0` for a seemingly noop transmute:\r\n```rust\r\nfn foo(x: ~[u8]) -> ~str {unsafe{transmute(x)}}\r\n```\r\n```ll\r\ndefine internal { i64, i64, [0 x i8] }* @foo::h5f52f1de17121161af::v0.0({ i64, %tydesc*, i8*, i8*, i8 }*, { i64, i64, [0 x i8] }* noalias) unnamed_addr #4 {\r\n\"function top level\":\r\n  %__arg = alloca { i64, i64, [0 x i8] }*\r\n  %__self = alloca { i64, i64, [0 x i8] }*\r\n  %2 = alloca { i8*, i32 }\r\n  store { i64, i64, [0 x i8] }* %1, { i64, i64, [0 x i8] }** %__arg\r\n  %3 = load { i64, i64, [0 x i8] }** %__arg\r\n  store { i64, i64, [0 x i8] }* %3, { i64, i64, [0 x i8] }** %__self\r\n  %4 = bitcast { i64, i64, [0 x i8] }** %__arg to i8*\r\n  call void @llvm.memset.p0i8.i64(i8* %4, i8 0, i64 8, i32 8, i1 false)\r\n  %5 = load { i64, i64, [0 x i8] }** %__self\r\n  br label %\"normal return\"\r\n\r\n\"normal return\":                                  ; preds = %\"function top level\"\r\n  %6 = bitcast { i64, i64, [0 x i8] }** %__arg to i32**\r\n  call void @\"_$UP$u32::glue_drop::hb6a3c7b062d25f8far\"({}* null, i32** %6)\r\n  ret { i64, i64, [0 x i8] }* %5\r\n\r\nunwind:                                           ; No predecessors!\r\n  %7 = landingpad { i8*, i32 } personality i32 (i32, i32, i64, %\"struct.std::rt::unwind::libunwind::_Unwind_Exception[#1]\"*, %\"enum.std::rt::unwind::libunwind::_Unwind_Context[#1]\"*)* @rust_eh_personality\r\n          cleanup\r\n  store { i8*, i32 } %7, { i8*, i32 }* %2\r\n  br label %cleanup\r\n\r\ncleanup:                                          ; preds = %unwind\r\n  %8 = bitcast { i64, i64, [0 x i8] }** %__arg to i32**\r\n  call void @\"_$UP$u32::glue_drop::hb6a3c7b062d25f8far\"({}* null, i32** %8)\r\n  %9 = load { i8*, i32 }* %2\r\n  resume { i8*, i32 } %9\r\n}\r\n```\r\nWherever `x` is moved out of, a `memset` call is used to zero the pointer, to \"cancel the cleanup\" (drop glue ignores NULL pointers and objects with a drop flag of 0).\r\n\r\nThe generated IR could look like this, without affecting semantics:\r\n```ll\r\ndefine internal { i64, i64, [0 x i8] }* @foo::h5f52f1de17121161af::v0.0({ i64, %tydesc*, i8*, i8*, i8 }*, { i64, i64, [0 x i8] }* noalias) unnamed_addr #4 {\r\n\"function top level\":\r\n  %__self = alloca { i64, i64, [0 x i8] }*\r\n  store { i64, i64, [0 x i8] }* %1 { i64, i64, [0 x i8] }** %__self\r\n  %2 = load { i64, i64, [0 x i8] }** %__self\r\n  br label %\"normal return\"\r\n\r\n\"normal return\":                                  ; preds = %\"function top level\"\r\n  ret { i64, i64, [0 x i8] }* %2\r\n```\r\n(it might be even possible to remove the alloca used for the inlined `transmute` call)\r\n\r\nThe reason I wasn't able to implement this behavior in #11252 is the differing scope between the cleanup creation and the cleanup cancellation. It becomes obvious when we have multiple branches:\r\n```rust\r\nfn foo<T: Clone>(x: T) {\r\n    if rand() % 1 == 0 {\r\n        x // moves out of x (zeroes x to cancel cleanup)\r\n    } else {\r\n        x.clone() // doesn't move out of x\r\n    }\r\n}\r\n```\r\n@huonw recalled someone mentioning requiring to move out of `x` in both branches, but I don't know if that's a viable solution.\r\n\r\ncc @nikomatsakis @pcwalton @thestinger"},"comment":{"url":"https://api.github.com/repos/rust-lang/rust/issues/comments/178734490","html_url":"https://github.com/rust-lang/rust/issues/11445#issuecomment-178734490","issue_url":"https://api.github.com/repos/rust-lang/rust/issues/11445","id":178734490,"user":{"login":"eddyb","id":77424,"avatar_url":"https://avatars.githubusercontent.com/u/77424?v=3","gravatar_id":"","url":"https://api.github.com/users/eddyb","html_url":"https://github.com/eddyb","followers_url":"https://api.github.com/users/eddyb/followers","following_url":"https://api.github.com/users/eddyb/following{/other_user}","gists_url":"https://api.github.com/users/eddyb/gists{/gist_id}","starred_url":"https://api.github.com/users/eddyb/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/eddyb/subscriptions","organizations_url":"https://api.github.com/users/eddyb/orgs","repos_url":"https://api.github.com/users/eddyb/repos","events_url":"https://api.github.com/users/eddyb/events{/privacy}","received_events_url":"https://api.github.com/users/eddyb/received_events","type":"User","site_admin":false},"created_at":"2016-02-02T18:20:52Z","updated_at":"2016-02-02T18:20:52Z","body":"Yes, static and dynamic drop have both gotten much better since (although filling drop still exists in marginal cases)."}}