|
11 | 11 | // |
12 | 12 |
|
13 | 13 | use super::*; |
14 | | -use crate::parse::ast::{AssignOp, ExprKind, ExternalDecl, FunctionDef, Parameter, UnaryOp}; |
| 14 | +use crate::parse::ast::{ |
| 15 | + AssignOp, BlockItem, Declaration, ExprKind, ExternalDecl, FunctionDef, InitDeclarator, |
| 16 | + Parameter, UnaryOp, |
| 17 | +}; |
15 | 18 | use crate::strings::StringTable; |
| 19 | +use crate::types::Type; |
16 | 20 |
|
17 | 21 | /// Create a default position for test code |
18 | 22 | fn test_pos() -> Position { |
@@ -2422,3 +2426,110 @@ fn test_ternary_with_post_increment_uses_phi() { |
2422 | 2426 | ir |
2423 | 2427 | ); |
2424 | 2428 | } |
| 2429 | + |
| 2430 | +// ============================================================================ |
| 2431 | +// String literal initialization tests |
| 2432 | +// ============================================================================ |
| 2433 | + |
| 2434 | +#[test] |
| 2435 | +fn test_string_literal_char_array_init() { |
| 2436 | + // Test that `char arr[6] = "hello";` generates store instructions for each byte |
| 2437 | + // plus null terminator (6 stores total: 'h', 'e', 'l', 'l', 'o', '\0') |
| 2438 | + let mut strings = StringTable::new(); |
| 2439 | + let mut types = TypeTable::new(64); |
| 2440 | + let test_id = strings.intern("test"); |
| 2441 | + let arr_id = strings.intern("arr"); |
| 2442 | + |
| 2443 | + // Create char[6] type |
| 2444 | + let char_arr_type = types.intern(Type::array(types.char_id, 6)); |
| 2445 | + |
| 2446 | + // Function: int test() { char arr[6] = "hello"; return 0; } |
| 2447 | + let func = FunctionDef { |
| 2448 | + return_type: types.int_id, |
| 2449 | + name: test_id, |
| 2450 | + params: vec![], |
| 2451 | + body: Stmt::Block(vec![ |
| 2452 | + BlockItem::Declaration(Declaration { |
| 2453 | + declarators: vec![InitDeclarator { |
| 2454 | + name: arr_id, |
| 2455 | + typ: char_arr_type, |
| 2456 | + init: Some(Expr::typed( |
| 2457 | + ExprKind::StringLit("hello".to_string()), |
| 2458 | + types.char_ptr_id, |
| 2459 | + test_pos(), |
| 2460 | + )), |
| 2461 | + vla_sizes: vec![], |
| 2462 | + }], |
| 2463 | + }), |
| 2464 | + BlockItem::Statement(Stmt::Return(Some(Expr::int(0, &types)))), |
| 2465 | + ]), |
| 2466 | + pos: test_pos(), |
| 2467 | + }; |
| 2468 | + let tu = TranslationUnit { |
| 2469 | + items: vec![ExternalDecl::FunctionDef(func)], |
| 2470 | + }; |
| 2471 | + |
| 2472 | + let module = test_linearize(&tu, &types, &strings); |
| 2473 | + let ir = format!("{}", module); |
| 2474 | + |
| 2475 | + // Should have 6 store instructions (5 chars + null terminator) |
| 2476 | + let store_count = ir.matches("store").count(); |
| 2477 | + assert!( |
| 2478 | + store_count >= 6, |
| 2479 | + "Expected at least 6 store instructions for 'hello' + null, got {}: {}", |
| 2480 | + store_count, |
| 2481 | + ir |
| 2482 | + ); |
| 2483 | +} |
| 2484 | + |
| 2485 | +#[test] |
| 2486 | +fn test_string_literal_char_pointer_init() { |
| 2487 | + // Test that `char *p = "hello";` generates a single store of the string address |
| 2488 | + let mut strings = StringTable::new(); |
| 2489 | + let types = TypeTable::new(64); |
| 2490 | + let test_id = strings.intern("test"); |
| 2491 | + let p_id = strings.intern("p"); |
| 2492 | + |
| 2493 | + // Function: int test() { char *p = "hello"; return 0; } |
| 2494 | + let func = FunctionDef { |
| 2495 | + return_type: types.int_id, |
| 2496 | + name: test_id, |
| 2497 | + params: vec![], |
| 2498 | + body: Stmt::Block(vec![ |
| 2499 | + BlockItem::Declaration(Declaration { |
| 2500 | + declarators: vec![InitDeclarator { |
| 2501 | + name: p_id, |
| 2502 | + typ: types.char_ptr_id, |
| 2503 | + init: Some(Expr::typed( |
| 2504 | + ExprKind::StringLit("hello".to_string()), |
| 2505 | + types.char_ptr_id, |
| 2506 | + test_pos(), |
| 2507 | + )), |
| 2508 | + vla_sizes: vec![], |
| 2509 | + }], |
| 2510 | + }), |
| 2511 | + BlockItem::Statement(Stmt::Return(Some(Expr::int(0, &types)))), |
| 2512 | + ]), |
| 2513 | + pos: test_pos(), |
| 2514 | + }; |
| 2515 | + let tu = TranslationUnit { |
| 2516 | + items: vec![ExternalDecl::FunctionDef(func)], |
| 2517 | + }; |
| 2518 | + |
| 2519 | + let module = test_linearize(&tu, &types, &strings); |
| 2520 | + let ir = format!("{}", module); |
| 2521 | + |
| 2522 | + // Should have a store instruction for the pointer (storing the string address) |
| 2523 | + assert!( |
| 2524 | + ir.contains("store"), |
| 2525 | + "Pointer init should have a store instruction: {}", |
| 2526 | + ir |
| 2527 | + ); |
| 2528 | + |
| 2529 | + // The module should contain the string literal (strings are stored in module) |
| 2530 | + assert!( |
| 2531 | + !module.strings.is_empty(), |
| 2532 | + "Module should contain string literal: {}", |
| 2533 | + ir |
| 2534 | + ); |
| 2535 | +} |
0 commit comments