From dd39718073b81d8087d31f464964770d15ca7e3d Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Fri, 15 May 2026 17:28:23 +0100 Subject: [PATCH 1/4] Support implicit conversion in std::vector constructor --- rules/vector/ir_refcount.json | 163 ++++++------------------ rules/vector/ir_unsafe.json | 232 +++++++++++++++------------------- rules/vector/src.cpp | 7 +- rules/vector/tgt_refcount.rs | 14 +- rules/vector/tgt_unsafe.rs | 14 +- 5 files changed, 151 insertions(+), 279 deletions(-) diff --git a/rules/vector/ir_refcount.json b/rules/vector/ir_refcount.json index 0f533932..1010904c 100644 --- a/rules/vector/ir_refcount.json +++ b/rules/vector/ir_refcount.json @@ -1235,12 +1235,43 @@ "method_call": { "receiver": [ { - "text": "__a0" + "method_call": { + "receiver": [ + { + "generic": 1 + }, + { + "text": "::try_from(" + }, + { + "method_call": { + "receiver": [ + { + "text": "__a0" + } + ], + "body": [ + { + "text": ".read()" + } + ] + } + }, + { + "text": ")" + } + ], + "body": [ + { + "text": ".ok()" + } + ] + } } ], "body": [ { - "text": ".read()" + "text": ".unwrap()" } ] } @@ -1257,6 +1288,9 @@ ], "generics": { "T1": [ + "TryFrom" + ], + "T2": [ "Clone", "ByteRepr" ] @@ -1264,11 +1298,11 @@ "multi_statement": true, "params": { "a0": { - "type": "Ptr", + "type": "Ptr", "is_refcount_pointer": true }, "a1": { - "type": "Ptr", + "type": "Ptr", "is_refcount_pointer": true } }, @@ -1276,127 +1310,6 @@ "type": "Vec" } }, - "f39": { - "body": [ - { - "text": "let mut __a0 = " - }, - { - "method_call": { - "receiver": [ - { - "placeholder": { - "arg": 0, - "access": "read" - } - } - ], - "body": [ - { - "text": ".clone()" - } - ] - } - }, - { - "text": ";\n let mut __out = Vec::with_capacity(" - }, - { - "method_call": { - "receiver": [ - { - "placeholder": { - "arg": 1, - "access": "read" - } - } - ], - "body": [ - { - "text": ".get_offset()" - } - ] - } - }, - { - "text": " - " - }, - { - "method_call": { - "receiver": [ - { - "text": "__a0" - } - ], - "body": [ - { - "text": ".get_offset()" - } - ] - } - }, - { - "text": ");\n while __a0 != " - }, - { - "placeholder": { - "arg": 1, - "access": "read" - } - }, - { - "text": " {\n " - }, - { - "method_call": { - "receiver": [ - { - "text": "__out" - } - ], - "body": [ - { - "text": ".push(" - }, - { - "method_call": { - "receiver": [ - { - "text": "__a0" - } - ], - "body": [ - { - "text": ".read()" - } - ] - } - }, - { - "text": " as i32)" - } - ] - } - }, - { - "text": ";\n __a0 += 1;\n }\n __out" - } - ], - "multi_statement": true, - "params": { - "a0": { - "type": "Ptr", - "is_refcount_pointer": true - }, - "a1": { - "type": "Ptr", - "is_refcount_pointer": true - } - }, - "return_type": { - "type": "Vec" - } - }, "f40": { "body": [ { diff --git a/rules/vector/ir_unsafe.json b/rules/vector/ir_unsafe.json index f3b3ed37..fa40797c 100644 --- a/rules/vector/ir_unsafe.json +++ b/rules/vector/ir_unsafe.json @@ -1436,42 +1436,115 @@ { "method_call": { "receiver": [ - { - "text": "core::slice::from_raw_parts(" - }, - { - "placeholder": { - "arg": 0, - "access": "read" - } - }, - { - "text": ", " - }, { "method_call": { "receiver": [ { - "text": "(" - }, - { - "placeholder": { - "arg": 1, - "access": "write" + "method_call": { + "receiver": [ + { + "text": "core::slice::from_raw_parts(" + }, + { + "placeholder": { + "arg": 0, + "access": "read" + } + }, + { + "text": ", " + }, + { + "method_call": { + "receiver": [ + { + "text": "(" + }, + { + "placeholder": { + "arg": 1, + "access": "write" + } + }, + { + "text": ")" + } + ], + "body": [ + { + "text": ".offset_from(" + }, + { + "placeholder": { + "arg": 0, + "access": "read" + } + }, + { + "text": ")" + } + ] + } + }, + { + "text": " as usize)" + } + ], + "body": [ + { + "text": ".iter()" + } + ] } - }, - { - "text": ")" } ], "body": [ { - "text": ".offset_from(" + "text": ".map(|x| " }, { - "placeholder": { - "arg": 0, - "access": "read" + "method_call": { + "receiver": [ + { + "method_call": { + "receiver": [ + { + "generic": 1 + }, + { + "text": "::try_from(" + }, + { + "method_call": { + "receiver": [ + { + "text": "x" + } + ], + "body": [ + { + "text": ".clone()" + } + ] + } + }, + { + "text": ")" + } + ], + "body": [ + { + "text": ".ok()" + } + ] + } + } + ], + "body": [ + { + "text": ".unwrap()" + } + ] } }, { @@ -1479,14 +1552,11 @@ } ] } - }, - { - "text": " as usize)" } ], "body": [ { - "text": ".to_vec()" + "text": ".collect()" } ] } @@ -1494,16 +1564,19 @@ ], "generics": { "T1": [ + "TryFrom" + ], + "T2": [ "Clone" ] }, "params": { "a0": { - "type": "*mut T1", + "type": "*mut T2", "is_unsafe_pointer": true }, "a1": { - "type": "*mut T1", + "type": "*mut T2", "is_unsafe_pointer": true } }, @@ -1569,103 +1642,6 @@ "type": "Vec" } }, - "f39": { - "body": [ - { - "method_call": { - "receiver": [ - { - "method_call": { - "receiver": [ - { - "method_call": { - "receiver": [ - { - "text": "core::slice::from_raw_parts(" - }, - { - "placeholder": { - "arg": 0, - "access": "read" - } - }, - { - "text": ", " - }, - { - "method_call": { - "receiver": [ - { - "text": "(" - }, - { - "placeholder": { - "arg": 1, - "access": "write" - } - }, - { - "text": ")" - } - ], - "body": [ - { - "text": ".offset_from(" - }, - { - "placeholder": { - "arg": 0, - "access": "read" - } - }, - { - "text": ")" - } - ] - } - }, - { - "text": " as usize)" - } - ], - "body": [ - { - "text": ".iter()" - } - ] - } - } - ], - "body": [ - { - "text": ".map(|&x| x as i32)" - } - ] - } - } - ], - "body": [ - { - "text": ".collect()" - } - ] - } - } - ], - "params": { - "a0": { - "type": "*mut u32", - "is_unsafe_pointer": true - }, - "a1": { - "type": "*mut u32", - "is_unsafe_pointer": true - } - }, - "return_type": { - "type": "Vec" - } - }, "f4": { "body": [ { diff --git a/rules/vector/src.cpp b/rules/vector/src.cpp index 91ba5851..59037ff9 100644 --- a/rules/vector/src.cpp +++ b/rules/vector/src.cpp @@ -171,7 +171,8 @@ std::vector f36(const std::initializer_list &a0) { return std::vector(a0); } -template std::vector f37(T1 *first, T1 *last) { +template +std::vector f37(T2 *first, T2 *last) { return std::vector(first, last); } @@ -179,10 +180,6 @@ std::vector f38(std::size_t n, const bool &value) { return std::vector(n, value); } -std::vector f39(unsigned int *first, unsigned int *last) { - return std::vector(first, last); -} - template const T1 *f40(T1 const (&a0)[T2]) { return std::end(a0); } diff --git a/rules/vector/tgt_refcount.rs b/rules/vector/tgt_refcount.rs index 99e8158a..abdee1c7 100644 --- a/rules/vector/tgt_refcount.rs +++ b/rules/vector/tgt_refcount.rs @@ -122,21 +122,11 @@ fn f35(a0: Ptr, a1: Ptr) -> Vec { __out } -fn f37(a0: Ptr, a1: Ptr) -> Vec { +fn f37, T2: Clone + ByteRepr>(a0: Ptr, a1: Ptr) -> Vec { let mut __a0 = a0.clone(); let mut __out = Vec::with_capacity(a1.get_offset() - __a0.get_offset()); while __a0 != a1 { - __out.push(__a0.read()); - __a0 += 1; - } - __out -} - -fn f39(a0: Ptr, a1: Ptr) -> Vec { - let mut __a0 = a0.clone(); - let mut __out = Vec::with_capacity(a1.get_offset() - __a0.get_offset()); - while __a0 != a1 { - __out.push(__a0.read() as i32); + __out.push(T1::try_from(__a0.read()).ok().unwrap()); __a0 += 1; } __out diff --git a/rules/vector/tgt_unsafe.rs b/rules/vector/tgt_unsafe.rs index 2b4559f3..e34bf4ee 100644 --- a/rules/vector/tgt_unsafe.rs +++ b/rules/vector/tgt_unsafe.rs @@ -142,21 +142,17 @@ unsafe fn f36(a0: Vec) -> Vec { a0 } -unsafe fn f37(a0: *mut T1, a1: *mut T1) -> Vec { - core::slice::from_raw_parts(a0, (a1).offset_from(a0) as usize).to_vec() +unsafe fn f37, T2: Clone>(a0: *mut T2, a1: *mut T2) -> Vec { + core::slice::from_raw_parts(a0, (a1).offset_from(a0) as usize) + .iter() + .map(|x| T1::try_from(x.clone()).ok().unwrap()) + .collect() } unsafe fn f38(a0: usize, a1: bool) -> Vec { (0..(a0) as usize).map(|_| a1).collect::>() } -unsafe fn f39(a0: *mut u32, a1: *mut u32) -> Vec { - core::slice::from_raw_parts(a0, (a1).offset_from(a0) as usize) - .iter() - .map(|&x| x as i32) - .collect() -} - unsafe fn f40(a0: Vec) -> *const T1 { a0.as_ptr().add(a0.len()) } From d11f8f57878bc8d16e84567c0bbd958810f1f84e Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Fri, 15 May 2026 17:31:30 +0100 Subject: [PATCH 2/4] Add test for implicit conversion in vector ctor --- .../out/refcount/vector_iter_range_ctor.rs | 75 +++++++++++++++++++ .../unit/out/unsafe/vector_iter_range_ctor.rs | 53 +++++++++++++ tests/unit/vector_iter_range_ctor.cpp | 26 +++++++ 3 files changed, 154 insertions(+) create mode 100644 tests/unit/out/refcount/vector_iter_range_ctor.rs create mode 100644 tests/unit/out/unsafe/vector_iter_range_ctor.rs create mode 100644 tests/unit/vector_iter_range_ctor.cpp diff --git a/tests/unit/out/refcount/vector_iter_range_ctor.rs b/tests/unit/out/refcount/vector_iter_range_ctor.rs new file mode 100644 index 00000000..dd69a3b2 --- /dev/null +++ b/tests/unit/out/refcount/vector_iter_range_ctor.rs @@ -0,0 +1,75 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let src: Value> = Rc::new(RefCell::new(Box::new([1_u32, 2_u32, 3_u32]))); + let v1: Value> = Rc::new(RefCell::new({ + let mut __a0 = (src.as_pointer() as Ptr).clone(); + let mut __out = Vec::with_capacity( + (src.as_pointer() as Ptr) + .offset((3) as isize) + .get_offset() + - __a0.get_offset(), + ); + while __a0 != (src.as_pointer() as Ptr).offset((3) as isize) { + __out.push(u32::try_from(__a0.read()).ok().unwrap()); + __a0 += 1; + } + __out + })); + assert!(((*v1.borrow()).len() as u64 == 3_u64)); + assert!( + ((((v1.as_pointer() as Ptr).offset(0_u64 as isize).read()) == 1_u32) + && (((v1.as_pointer() as Ptr).offset(1_u64 as isize).read()) == 2_u32)) + && (((v1.as_pointer() as Ptr).offset(2_u64 as isize).read()) == 3_u32) + ); + let v2: Value> = Rc::new(RefCell::new({ + let mut __a0 = (src.as_pointer() as Ptr).clone(); + let mut __out = Vec::with_capacity( + (src.as_pointer() as Ptr) + .offset((3) as isize) + .get_offset() + - __a0.get_offset(), + ); + while __a0 != (src.as_pointer() as Ptr).offset((3) as isize) { + __out.push(u64::try_from(__a0.read()).ok().unwrap()); + __a0 += 1; + } + __out + })); + assert!(((*v2.borrow()).len() as u64 == 3_u64)); + assert!( + ((((v2.as_pointer() as Ptr).offset(0_u64 as isize).read()) == 1_u64) + && (((v2.as_pointer() as Ptr).offset(1_u64 as isize).read()) == 2_u64)) + && (((v2.as_pointer() as Ptr).offset(2_u64 as isize).read()) == 3_u64) + ); + let v3: Value> = Rc::new(RefCell::new({ + let mut __a0 = (src.as_pointer() as Ptr).clone(); + let mut __out = Vec::with_capacity( + (src.as_pointer() as Ptr) + .offset((3) as isize) + .get_offset() + - __a0.get_offset(), + ); + while __a0 != (src.as_pointer() as Ptr).offset((3) as isize) { + __out.push(i32::try_from(__a0.read()).ok().unwrap()); + __a0 += 1; + } + __out + })); + assert!(((*v3.borrow()).len() as u64 == 3_u64)); + assert!( + ((((v3.as_pointer() as Ptr).offset(0_u64 as isize).read()) == 1) + && (((v3.as_pointer() as Ptr).offset(1_u64 as isize).read()) == 2)) + && (((v3.as_pointer() as Ptr).offset(2_u64 as isize).read()) == 3) + ); + return 0; +} diff --git a/tests/unit/out/unsafe/vector_iter_range_ctor.rs b/tests/unit/out/unsafe/vector_iter_range_ctor.rs new file mode 100644 index 00000000..bd7b981b --- /dev/null +++ b/tests/unit/out/unsafe/vector_iter_range_ctor.rs @@ -0,0 +1,53 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut src: [u32; 3] = [1_u32, 2_u32, 3_u32]; + let mut v1: Vec = core::slice::from_raw_parts( + src.as_mut_ptr(), + (src.as_mut_ptr().offset((3) as isize)).offset_from(src.as_mut_ptr()) as usize, + ) + .iter() + .map(|x| u32::try_from(x.clone()).ok().unwrap()) + .collect(); + assert!(((v1.len() as u64) == (3_u64))); + assert!( + (((v1[(0_u64) as usize]) == (1_u32)) && ((v1[(1_u64) as usize]) == (2_u32))) + && ((v1[(2_u64) as usize]) == (3_u32)) + ); + let mut v2: Vec = core::slice::from_raw_parts( + src.as_mut_ptr(), + (src.as_mut_ptr().offset((3) as isize)).offset_from(src.as_mut_ptr()) as usize, + ) + .iter() + .map(|x| u64::try_from(x.clone()).ok().unwrap()) + .collect(); + assert!(((v2.len() as u64) == (3_u64))); + assert!( + (((v2[(0_u64) as usize]) == (1_u64)) && ((v2[(1_u64) as usize]) == (2_u64))) + && ((v2[(2_u64) as usize]) == (3_u64)) + ); + let mut v3: Vec = core::slice::from_raw_parts( + src.as_mut_ptr(), + (src.as_mut_ptr().offset((3) as isize)).offset_from(src.as_mut_ptr()) as usize, + ) + .iter() + .map(|x| i32::try_from(x.clone()).ok().unwrap()) + .collect(); + assert!(((v3.len() as u64) == (3_u64))); + assert!( + (((v3[(0_u64) as usize]) == (1)) && ((v3[(1_u64) as usize]) == (2))) + && ((v3[(2_u64) as usize]) == (3)) + ); + return 0; +} diff --git a/tests/unit/vector_iter_range_ctor.cpp b/tests/unit/vector_iter_range_ctor.cpp new file mode 100644 index 00000000..313c7835 --- /dev/null +++ b/tests/unit/vector_iter_range_ctor.cpp @@ -0,0 +1,26 @@ +#include + +#include +#include +#include + +int main() { + uint32_t src[3] = {1, 2, 3}; + + // Same-type iterator-range constructor. + std::vector v1(src, src + 3); + assert(v1.size() == 3); + assert(v1[0] == 1 && v1[1] == 2 && v1[2] == 3); + + // Cross-type widening (uint32_t -> size_t). + std::vector v2(src, src + 3); + assert(v2.size() == 3); + assert(v2[0] == 1 && v2[1] == 2 && v2[2] == 3); + + // Cross-type sign-flip (uint32_t -> int). + std::vector v3(src, src + 3); + assert(v3.size() == 3); + assert(v3[0] == 1 && v3[1] == 2 && v3[2] == 3); + + return 0; +} From 6459f366dbf2e7f83ba1a2be8b2bae91d7400855 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Fri, 15 May 2026 17:35:41 +0100 Subject: [PATCH 3/4] clang-format --- tests/unit/vector_iter_range_ctor.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/unit/vector_iter_range_ctor.cpp b/tests/unit/vector_iter_range_ctor.cpp index 313c7835..02848ca1 100644 --- a/tests/unit/vector_iter_range_ctor.cpp +++ b/tests/unit/vector_iter_range_ctor.cpp @@ -1,5 +1,4 @@ #include - #include #include #include From 5dd038fc6c254f1fb27152bdb15ba427e59a448c Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Sat, 16 May 2026 12:48:26 +0100 Subject: [PATCH 4/4] Update tests --- tests/unit/out/refcount/push_emplace_back.rs | 4 ++-- tests/unit/out/unsafe/push_emplace_back.rs | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/unit/out/refcount/push_emplace_back.rs b/tests/unit/out/refcount/push_emplace_back.rs index 190674d7..5633e699 100644 --- a/tests/unit/out/refcount/push_emplace_back.rs +++ b/tests/unit/out/refcount/push_emplace_back.rs @@ -88,7 +88,7 @@ pub fn push_local_from_field_1(jpg: Ptr, cond: bool) { - __a0.get_offset(), ); while __a0 != (head.as_pointer() as Ptr).offset((3) as isize) { - __out.push(__a0.read()); + __out.push(u8::try_from(__a0.read()).ok().unwrap()); __a0 += 1; } __out @@ -134,7 +134,7 @@ pub fn emplace_local_from_field_4(jpg: Ptr, cond: bool) { - __a0.get_offset(), ); while __a0 != (head.as_pointer() as Ptr).offset((3) as isize) { - __out.push(__a0.read()); + __out.push(u8::try_from(__a0.read()).ok().unwrap()); __a0 += 1; } __out diff --git a/tests/unit/out/unsafe/push_emplace_back.rs b/tests/unit/out/unsafe/push_emplace_back.rs index a026cbb0..e044d375 100644 --- a/tests/unit/out/unsafe/push_emplace_back.rs +++ b/tests/unit/out/unsafe/push_emplace_back.rs @@ -39,7 +39,9 @@ pub unsafe fn push_local_from_field_1(mut jpg: *mut JPEGData, mut cond: bool) { head.as_mut_ptr(), (head.as_mut_ptr().offset((3) as isize)).offset_from(head.as_mut_ptr()) as usize, ) - .to_vec(), + .iter() + .map(|x| u8::try_from(x.clone()).ok().unwrap()) + .collect(), ); } pub unsafe fn shrink_through_ptr_2(mut comps: *mut Vec) { @@ -61,7 +63,9 @@ pub unsafe fn emplace_local_from_field_4(mut jpg: *mut JPEGData, mut cond: bool) head.as_mut_ptr(), (head.as_mut_ptr().offset((3) as isize)).offset_from(head.as_mut_ptr()) as usize, ) - .to_vec(), + .iter() + .map(|x| u8::try_from(x.clone()).ok().unwrap()) + .collect(), ); } pub unsafe fn nested_emplace_move_5(mut bw: *mut Writer) {