{"action":"created","issue":{"url":"https://api.github.com/repos/rust-lang/rust/issues/21812","labels_url":"https://api.github.com/repos/rust-lang/rust/issues/21812/labels{/name}","comments_url":"https://api.github.com/repos/rust-lang/rust/issues/21812/comments","events_url":"https://api.github.com/repos/rust-lang/rust/issues/21812/events","html_url":"https://github.com/rust-lang/rust/issues/21812","id":56130553,"number":21812,"title":"Variadic argument passing is incorrect for structs","user":{"login":"tsion","id":26806,"avatar_url":"https://avatars.githubusercontent.com/u/26806?v=3","gravatar_id":"","url":"https://api.github.com/users/tsion","html_url":"https://github.com/tsion","followers_url":"https://api.github.com/users/tsion/followers","following_url":"https://api.github.com/users/tsion/following{/other_user}","gists_url":"https://api.github.com/users/tsion/gists{/gist_id}","starred_url":"https://api.github.com/users/tsion/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tsion/subscriptions","organizations_url":"https://api.github.com/users/tsion/orgs","repos_url":"https://api.github.com/users/tsion/repos","events_url":"https://api.github.com/users/tsion/events{/privacy}","received_events_url":"https://api.github.com/users/tsion/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":1,"created_at":"2015-01-31T16:41:11Z","updated_at":"2015-01-31T18:27:17Z","closed_at":null,"body":"Rust wisely tells us to cast `u8` and `u16` to `c_int` (aka `u32`) and `f32` to `c_double` (aka `f64`) when passing values of these types in variadic argument lists, since C expects this kind of type promotion to occur for varargs. But one can get around this and accidentally break things by wrapping the type in a newtype-style struct:\r\n\r\n``` rust\r\nextern crate libc;\r\nuse libc::{c_char, c_int, c_double};\r\n\r\nextern {\r\n    fn printf(fmt: *const c_char, ...) -> c_int;\r\n}\r\n\r\nfn main() {\r\n    let x: f32 = 1f32 / 2f32;\r\n    let fmt = b\"1 / 2 = %f\\n\\0\".as_ptr() as *mut c_char;\r\n    struct Oops(f32);\r\n    unsafe {\r\n        // printf(fmt, x); // error: can't pass an f32 to variadic function, cast to c_double\r\n        printf(fmt, x as c_double); // 1 / 2 = 0.500000\r\n        printf(fmt, Oops(x));       // 1 / 2 = 0.000000 (wrong!)\r\n    }\r\n}\r\n```\r\n\r\nIt seems like struct/enum types should be disallowed from variadic argument lists entirely. The existing checks can be found [here](https://github.com/rust-lang/rust/blob/master/src/librustc_typeck/check/mod.rs#L2365-L2388)."},"comment":{"url":"https://api.github.com/repos/rust-lang/rust/issues/comments/72329464","html_url":"https://github.com/rust-lang/rust/issues/21812#issuecomment-72329464","issue_url":"https://api.github.com/repos/rust-lang/rust/issues/21812","id":72329464,"user":{"login":"Diggsey","id":451321,"avatar_url":"https://avatars.githubusercontent.com/u/451321?v=3","gravatar_id":"","url":"https://api.github.com/users/Diggsey","html_url":"https://github.com/Diggsey","followers_url":"https://api.github.com/users/Diggsey/followers","following_url":"https://api.github.com/users/Diggsey/following{/other_user}","gists_url":"https://api.github.com/users/Diggsey/gists{/gist_id}","starred_url":"https://api.github.com/users/Diggsey/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Diggsey/subscriptions","organizations_url":"https://api.github.com/users/Diggsey/orgs","repos_url":"https://api.github.com/users/Diggsey/repos","events_url":"https://api.github.com/users/Diggsey/events{/privacy}","received_events_url":"https://api.github.com/users/Diggsey/received_events","type":"User","site_admin":false},"created_at":"2015-01-31T18:27:17Z","updated_at":"2015-01-31T18:27:17Z","body":"printf and variants are not the only variadic functions. Structs/enums should not be disallowed from variadic argument lists.\r\n\r\nIsn't there already a lint to prevent non-\"repr(C)\" types from being passed to C functions. This should prevent passing newtypes or other structs/enums not designed for that.\r\n\r\nYou could argue for applying the same conversions to new-types, however for the moment I don't think rust recognises newtypes as special in any way, so it would be a little odd."}}