Skip to content

Commit 75c39e5

Browse files
authored
Merge pull request #496 from rustcoreutils/updates
[cc] ir and parser fixes
2 parents ad2df1f + 71493f7 commit 75c39e5

File tree

3 files changed

+362
-21
lines changed

3 files changed

+362
-21
lines changed

cc/ir/linearize.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1346,6 +1346,37 @@ impl<'a> Linearizer<'a> {
13461346
self.emit_aggregate_zero(sym_id, typ);
13471347
}
13481348
self.linearize_init_list(sym_id, typ, elements);
1349+
} else if let ExprKind::StringLit(s) = &init.kind {
1350+
// String literal initialization of char array
1351+
// Copy the string bytes to the local array
1352+
if self.types.kind(typ) == TypeKind::Array {
1353+
let elem_type = self.types.base_type(typ).unwrap_or(self.types.char_id);
1354+
let elem_size = self.types.size_bits(elem_type);
1355+
1356+
// Copy each byte from string literal to local array
1357+
for (i, byte) in s.bytes().enumerate() {
1358+
let byte_val = self.emit_const(byte as i64, elem_type);
1359+
self.emit(Instruction::store(
1360+
byte_val, sym_id, i as i64, elem_type, elem_size,
1361+
));
1362+
}
1363+
// Store null terminator
1364+
let null_val = self.emit_const(0, elem_type);
1365+
self.emit(Instruction::store(
1366+
null_val,
1367+
sym_id,
1368+
s.len() as i64,
1369+
elem_type,
1370+
elem_size,
1371+
));
1372+
} else {
1373+
// Pointer initialized with string literal - store the address
1374+
let val = self.linearize_expr(init);
1375+
let init_type = self.expr_type(init);
1376+
let converted = self.emit_convert(val, init_type, typ);
1377+
let size = self.types.size_bits(typ);
1378+
self.emit(Instruction::store(converted, sym_id, 0, typ, size));
1379+
}
13491380
} else if self.types.is_complex(typ) {
13501381
// Complex type initialization - linearize_expr returns an address
13511382
// to a temp containing the complex value. Copy from temp to local.
@@ -3407,6 +3438,12 @@ impl<'a> Linearizer<'a> {
34073438
let elem_type = self.types.base_type(arg_type).unwrap_or(self.types.int_id);
34083439
arg_types_vec.push(self.types.pointer_to(elem_type));
34093440
self.linearize_expr(a)
3441+
} else if arg_kind == TypeKind::VaList {
3442+
// va_list decay to pointer (C99 7.15.1)
3443+
// va_list is defined as __va_list_tag[1] (an array), so it decays to
3444+
// a pointer when passed to a function taking va_list parameter
3445+
arg_types_vec.push(self.types.pointer_to(arg_type));
3446+
self.linearize_lvalue(a)
34103447
} else if arg_kind == TypeKind::Function {
34113448
// Function decay to pointer (C99 6.3.2.1)
34123449
// Function names passed as arguments decay to function pointers

cc/ir/test_linearize.rs

Lines changed: 112 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,12 @@
1111
//
1212

1313
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+
};
1518
use crate::strings::StringTable;
19+
use crate::types::Type;
1620

1721
/// Create a default position for test code
1822
fn test_pos() -> Position {
@@ -2422,3 +2426,110 @@ fn test_ternary_with_post_increment_uses_phi() {
24222426
ir
24232427
);
24242428
}
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

Comments
 (0)