@@ -43,6 +43,7 @@ fn get_runners() -> Runners {
4343 runners. insert ( "--extended-regex-tests" , ( "Run extended regex tests" , extended_regex_tests) ) ;
4444 runners. insert ( "--mini-tests" , ( "Run mini tests" , mini_tests) ) ;
4545 runners. insert ( "--cargo-tests" , ( "Run cargo tests" , cargo_tests) ) ;
46+ runners. insert ( "--no-builtins-tests" , ( "Test #![no_builtins] attribute" , no_builtins_tests) ) ;
4647 runners
4748}
4849
@@ -317,6 +318,65 @@ fn maybe_run_command_in_vm(
317318 Ok ( ( ) )
318319}
319320
321+ /// Compile a source file to an object file and check if it contains a memset reference.
322+ fn object_has_memset (
323+ env : & Env ,
324+ args : & TestArg ,
325+ src_file : & str ,
326+ obj_file_name : & str ,
327+ ) -> Result < bool , String > {
328+ let cargo_target_dir = Path :: new ( & args. config_info . cargo_target_dir ) ;
329+ let obj_file = cargo_target_dir. join ( obj_file_name) ;
330+ let obj_file_str = obj_file. to_str ( ) . expect ( "obj_file to_str" ) ;
331+
332+ let mut command = args. config_info . rustc_command_vec ( ) ;
333+ command. extend_from_slice ( & [
334+ & src_file,
335+ & "--emit" ,
336+ & "obj" ,
337+ & "-O" ,
338+ & "--target" ,
339+ & args. config_info . target_triple ,
340+ & "-o" ,
341+ ] ) ;
342+ command. push ( & obj_file_str) ;
343+ run_command_with_env ( & command, None , Some ( env) ) ?;
344+
345+ let nm_output = run_command_with_env ( & [ & "nm" , & obj_file_str] , None , Some ( env) ) ?;
346+ let nm_stdout = String :: from_utf8_lossy ( & nm_output. stdout ) ;
347+
348+ Ok ( nm_stdout. contains ( "memset" ) )
349+ }
350+
351+ fn no_builtins_tests ( env : & Env , args : & TestArg ) -> Result < ( ) , String > {
352+ // Test that the #![no_builtins] attribute prevents GCC from replacing
353+ // code patterns (like loops) with calls to builtins (like memset).
354+ // See https://github.com/rust-lang/rustc_codegen_gcc/issues/570
355+
356+ // Test 1: WITH #![no_builtins] - memset should NOT be present
357+ println ! ( "[TEST] no_builtins attribute (with #![no_builtins])" ) ;
358+ let has_memset =
359+ object_has_memset ( env, args, "tests/no_builtins/no_builtins.rs" , "no_builtins_test.o" ) ?;
360+ if has_memset {
361+ return Err ( "no_builtins test FAILED: Found 'memset' in object file.\n \
362+ The #![no_builtins] attribute should prevent GCC from replacing \n \
363+ code patterns with builtin calls."
364+ . to_string ( ) ) ;
365+ }
366+
367+ // Test 2: WITHOUT #![no_builtins] - memset SHOULD be present
368+ println ! ( "[TEST] no_builtins attribute (without #![no_builtins])" ) ;
369+ let has_memset =
370+ object_has_memset ( env, args, "tests/no_builtins/with_builtins.rs" , "with_builtins_test.o" ) ?;
371+ if !has_memset {
372+ return Err ( "no_builtins test FAILED: 'memset' NOT found in object file.\n \
373+ Without #![no_builtins], GCC should replace the loop with memset."
374+ . to_string ( ) ) ;
375+ }
376+
377+ Ok ( ( ) )
378+ }
379+
320380fn std_tests ( env : & Env , args : & TestArg ) -> Result < ( ) , String > {
321381 let cargo_target_dir = Path :: new ( & args. config_info . cargo_target_dir ) ;
322382 // FIXME: create a function "display_if_not_quiet" or something along the line.
@@ -1248,6 +1308,7 @@ fn run_all(env: &Env, args: &TestArg) -> Result<(), String> {
12481308 test_libcore ( env, args) ?;
12491309 extended_sysroot_tests ( env, args) ?;
12501310 cargo_tests ( env, args) ?;
1311+ no_builtins_tests ( env, args) ?;
12511312 test_rustc ( env, args) ?;
12521313
12531314 Ok ( ( ) )
0 commit comments