fix(sema, ir): Potential elvate bugs

This commit is contained in:
2026-06-13 09:10:49 +08:00
parent 2d87760c79
commit 7bcf77f1c1
6 changed files with 135 additions and 34 deletions
+30
View File
@@ -205,6 +205,12 @@ impl Parser {
self.advance(1); self.advance(1);
return Ok(vec![]); return Ok(vec![]);
} }
if self.peek().value == TokenValue::TypeIdent(TypeIdent::Void)
&& self.peek_n(1).value == TokenValue::RParen
{
self.advance(2);
return Ok(vec![]);
}
let mut params = vec![]; let mut params = vec![];
loop { loop {
@@ -328,6 +334,30 @@ impl Parser {
Ok(Some(self.parse_expr()?)) Ok(Some(self.parse_expr()?))
} }
fn skip_initializer_list(&mut self) -> Result<(), ParseProcessError> {
let mut depth = 0usize;
loop {
let token = self.next().clone();
match token.value {
TokenValue::LBrace => depth += 1,
TokenValue::RBrace => {
depth -= 1;
if depth == 0 {
return Ok(());
}
}
TokenValue::Eof => {
self.diagnostics.add_from_frontend_error(
ParseError::ExpectedBefore(TokenValue::Eof, "`}`"),
token.span,
);
return Err(ParseProcessError::ErrorInMatch);
}
_ => {}
}
}
}
fn init_declarator_to_var_value( fn init_declarator_to_var_value(
&mut self, &mut self,
init_declarator: InitDeclarator, init_declarator: InitDeclarator,
+4
View File
@@ -59,6 +59,10 @@ impl Parser {
} }
fn parse_stmt(&mut self) -> Result<Statement, ParseProcessError> { fn parse_stmt(&mut self) -> Result<Statement, ParseProcessError> {
if self.peek().value == TokenValue::Semicolon {
self.advance(1);
return Ok(Statement::Block(BlockStmt { statements: vec![] }));
}
match self.parse_var_decl_stmt(ParseType::TryParse) { match self.parse_var_decl_stmt(ParseType::TryParse) {
Ok(var_decl) => return Ok(Statement::VarDecl(var_decl)), Ok(var_decl) => return Ok(Statement::VarDecl(var_decl)),
Err(ParseProcessError::ErrorInMatch) => return Err(ParseProcessError::ErrorInMatch), Err(ParseProcessError::ErrorInMatch) => return Err(ParseProcessError::ErrorInMatch),
+91 -26
View File
@@ -84,7 +84,7 @@ impl<'a> Generator<'a> {
} }
} else if let Some(init) = value.value { } else if let Some(init) = value.value {
self.current_exit_label.push(None); self.current_exit_label.push(None);
let (init_instrs, init_var) = match self.generate_expr(init) { let (mut init_instrs, init_var) = match self.generate_expr(init) {
Some(res) => res, Some(res) => res,
None => { None => {
self.current_exit_label.pop(); self.current_exit_label.pop();
@@ -93,8 +93,9 @@ impl<'a> Generator<'a> {
}; };
self.current_exit_label.pop(); self.current_exit_label.pop();
let target = self.var_manager.get_symbol(value.symbol).unwrap(); let target = self.var_manager.get_symbol(value.symbol).unwrap();
let init_var = self.coerce_value(&mut init_instrs, init_var.unwrap(), &target.data_type);
instrs.extend(init_instrs); instrs.extend(init_instrs);
instrs.push(IRInstr::Move(target, MoveRValue::Var(init_var.unwrap()))); instrs.push(IRInstr::Move(target, MoveRValue::Var(init_var)));
} }
} }
@@ -108,19 +109,26 @@ impl<'a> Generator<'a> {
let value = Self::const_init_value(operand)?; let value = Self::const_init_value(operand)?;
match op { match op {
AstUnaryOp::Add => Some(value), AstUnaryOp::Add => Some(value),
AstUnaryOp::Sub => value.checked_neg(), AstUnaryOp::Sub => Some(value.wrapping_neg()),
AstUnaryOp::Not => Some((value == 0) as i32), AstUnaryOp::Not => Some((value == 0) as i32),
} }
} }
HirExprValue::BinaryOp { lhs, op, rhs } => { HirExprValue::BinaryOp { lhs, op, rhs } => {
let lhs = Self::const_init_value(lhs)?; let lhs = Self::const_init_value(lhs)?;
match op {
AstBinaryOp::And if lhs == 0 => return Some(0),
AstBinaryOp::Or if lhs != 0 => return Some(1),
_ => {}
}
let rhs = Self::const_init_value(rhs)?; let rhs = Self::const_init_value(rhs)?;
match op { match op {
AstBinaryOp::Add => lhs.checked_add(rhs), AstBinaryOp::Add => Some(lhs.wrapping_add(rhs)),
AstBinaryOp::Sub => lhs.checked_sub(rhs), AstBinaryOp::Sub => Some(lhs.wrapping_sub(rhs)),
AstBinaryOp::Mul => lhs.checked_mul(rhs), AstBinaryOp::Mul => Some(lhs.wrapping_mul(rhs)),
AstBinaryOp::Div => lhs.checked_div(rhs), AstBinaryOp::Div if rhs != 0 => Some(lhs.wrapping_div(rhs)),
AstBinaryOp::Mod => lhs.checked_rem(rhs), AstBinaryOp::Div => None,
AstBinaryOp::Mod if rhs != 0 => Some(lhs.wrapping_rem(rhs)),
AstBinaryOp::Mod => None,
AstBinaryOp::Equal => Some((lhs == rhs) as i32), AstBinaryOp::Equal => Some((lhs == rhs) as i32),
AstBinaryOp::NotEqual => Some((lhs != rhs) as i32), AstBinaryOp::NotEqual => Some((lhs != rhs) as i32),
AstBinaryOp::Less => Some((lhs < rhs) as i32), AstBinaryOp::Less => Some((lhs < rhs) as i32),
@@ -214,7 +222,7 @@ impl<'a> Generator<'a> {
match return_stmt.value { match return_stmt.value {
Some(expr) => { Some(expr) => {
self.current_exit_label.push(None); self.current_exit_label.push(None);
let (value_instrs, value_var) = match self.generate_expr(expr) { let (mut value_instrs, value_var) = match self.generate_expr(expr) {
Some(res) => res, Some(res) => res,
None => { None => {
self.current_exit_label.pop(); self.current_exit_label.pop();
@@ -222,8 +230,10 @@ impl<'a> Generator<'a> {
} }
}; };
self.current_exit_label.pop(); self.current_exit_label.pop();
let target = func_exit.1.unwrap();
let value_var = self.coerce_value(&mut value_instrs, value_var.unwrap(), &target.data_type);
instrs.extend(value_instrs); instrs.extend(value_instrs);
instrs.push(IRInstr::Move(func_exit.1.unwrap(), MoveRValue::Var(value_var.unwrap()))); instrs.push(IRInstr::Move(target, MoveRValue::Var(value_var)));
} }
None => {}, None => {},
} }
@@ -387,6 +397,35 @@ impl<'a> Generator<'a> {
vec![] vec![]
} }
} }
fn coerce_value(&mut self, instrs: &mut Vec<IRInstr>, var: Variable, target_type: &IRType) -> Variable {
if &var.data_type == target_type {
return var;
}
match (&var.data_type, target_type) {
(IRType::I1, IRType::I32) => {
let dest = self.var_manager.declare_unamed_local(IRType::I32);
let true_label = self.request_label();
let false_label = self.request_label();
let final_label = self.request_label();
instrs.push(IRInstr::CondGoto(var, true_label, false_label));
instrs.push(IRInstr::Label(true_label));
instrs.push(IRInstr::Move(dest.clone(), MoveRValue::ConstInt(1)));
instrs.push(IRInstr::Goto(final_label));
instrs.push(IRInstr::Label(false_label));
instrs.push(IRInstr::Move(dest.clone(), MoveRValue::ConstInt(0)));
instrs.push(IRInstr::Goto(final_label));
instrs.push(IRInstr::Label(final_label));
dest
}
(IRType::I32, IRType::I1) => {
let dest = self.var_manager.declare_temp(IRType::I1);
instrs.push(IRInstr::Cmp(dest.clone(), VariableOrIntLit::Var(var), CmpOp::Ne, VariableOrIntLit::IntLit(0)));
dest
}
_ => var,
}
}
fn generate_expr(&mut self, expr: HirExpr) -> Option<(Vec<IRInstr>, Option<Variable>)> { fn generate_expr(&mut self, expr: HirExpr) -> Option<(Vec<IRInstr>, Option<Variable>)> {
// there may be some expr that doesn't produce value, like void func call // there may be some expr that doesn't produce value, like void func call
let (mut instrs, var) = match expr.value { let (mut instrs, var) = match expr.value {
@@ -414,6 +453,7 @@ impl<'a> Generator<'a> {
self.current_exit_label.push(None); self.current_exit_label.push(None);
let (mut instrs, rvalue_var) = self.generate_expr(*rvalue)?; let (mut instrs, rvalue_var) = self.generate_expr(*rvalue)?;
self.current_exit_label.pop(); self.current_exit_label.pop();
let rvalue_var = self.coerce_value(&mut instrs, rvalue_var.unwrap(), &lvalue_ty);
let (lvalue_instrs, target, is_addr) = self.generate_lvalue(*lvalue)?; let (lvalue_instrs, target, is_addr) = self.generate_lvalue(*lvalue)?;
instrs.extend(lvalue_instrs); instrs.extend(lvalue_instrs);
if is_addr { if is_addr {
@@ -509,17 +549,22 @@ impl<'a> Generator<'a> {
let operand_var = operand_var.unwrap(); let operand_var = operand_var.unwrap();
let dest_var = match op { let dest_var = match op {
AstUnaryOp::Add => { AstUnaryOp::Add => {
let dest_var = self.var_manager.declare_temp(operand_var.data_type.clone()); let target_ty = if operand_var.data_type == IRType::I1 { IRType::I32 } else { operand_var.data_type.clone() };
let operand_var = self.coerce_value(&mut instrs, operand_var, &target_ty);
let dest_var = self.var_manager.declare_temp(target_ty);
instrs.push(IRInstr::Move(dest_var.clone(), MoveRValue::Var(operand_var))); instrs.push(IRInstr::Move(dest_var.clone(), MoveRValue::Var(operand_var)));
dest_var dest_var
}, },
AstUnaryOp::Sub => { AstUnaryOp::Sub => {
let dest_var = self.var_manager.declare_temp(operand_var.data_type.clone()); let target_ty = if operand_var.data_type == IRType::I1 { IRType::I32 } else { operand_var.data_type.clone() };
let operand_var = self.coerce_value(&mut instrs, operand_var, &target_ty);
let dest_var = self.var_manager.declare_temp(target_ty);
instrs.push(IRInstr::Unary(dest_var.clone(), UnaryOp::Neg, operand_var)); instrs.push(IRInstr::Unary(dest_var.clone(), UnaryOp::Neg, operand_var));
dest_var dest_var
}, },
AstUnaryOp::Not => { AstUnaryOp::Not => {
let dest_var = self.var_manager.declare_unamed_local(operand_var.data_type.clone()); let dest_ty = if parent_is_logical { IRType::I1 } else { IRType::I32 };
let dest_var = self.var_manager.declare_unamed_local(dest_ty);
// child will do the cmp // child will do the cmp
if !parent_is_logical { if !parent_is_logical {
let exit = exit_passdown.unwrap(); // (false_exit, true_exit) (consider `not`) let exit = exit_passdown.unwrap(); // (false_exit, true_exit) (consider `not`)
@@ -626,9 +671,7 @@ impl<'a> Generator<'a> {
// do implicit convert if needed // do implicit convert if needed
// TODO: further check // TODO: further check
if !op.is_logical() && convert_to != left_var.data_type { if !op.is_logical() && convert_to != left_var.data_type {
let temp_var = self.var_manager.declare_temp(convert_to.clone()); left_var = self.coerce_value(&mut instrs, left_var, &convert_to);
instrs.push(IRInstr::Move(temp_var.clone(), MoveRValue::Var(left_var)));
left_var = temp_var;
} }
let result_type; let result_type;
match op { match op {
@@ -640,7 +683,13 @@ impl<'a> Generator<'a> {
result_type = IRType::I1; result_type = IRType::I1;
} }
} }
let dest_var = self.var_manager.declare_temp(result_type); let dest_var = if op.is_logical() && parent_exit.is_none() {
self.var_manager.declare_unamed_local(IRType::I32)
} else if op.is_logical() {
self.var_manager.declare_unamed_local(result_type)
} else {
self.var_manager.declare_temp(result_type)
};
match op { match op {
AstBinaryOp::And | AstBinaryOp::Or => { AstBinaryOp::And | AstBinaryOp::Or => {
instrs.push(IRInstr::Label(exit.unwrap().1)); instrs.push(IRInstr::Label(exit.unwrap().1));
@@ -666,9 +715,7 @@ impl<'a> Generator<'a> {
// true_exit: // true_exit:
instrs.extend(right_instrs); instrs.extend(right_instrs);
if !op.is_logical() && convert_to != right_var.data_type { if !op.is_logical() && convert_to != right_var.data_type {
let temp_var = self.var_manager.declare_temp(convert_to); right_var = self.coerce_value(&mut instrs, right_var, &convert_to);
instrs.push(IRInstr::Move(temp_var.clone(), MoveRValue::Var(right_var)));
right_var = temp_var;
} }
if !op.is_logical() { if !op.is_logical() {
if let Some((true_exit, false_exit)) = parent_exit { if let Some((true_exit, false_exit)) = parent_exit {
@@ -684,6 +731,17 @@ impl<'a> Generator<'a> {
} }
} }
if op.is_logical() { if op.is_logical() {
if parent_exit.is_none() {
let (true_exit, _, false_exit) = exit.unwrap();
let final_exit = self.request_label();
instrs.push(IRInstr::Label(true_exit));
instrs.push(IRInstr::Move(dest_var.clone(), MoveRValue::ConstInt(1)));
instrs.push(IRInstr::Goto(final_exit));
instrs.push(IRInstr::Label(false_exit));
instrs.push(IRInstr::Move(dest_var.clone(), MoveRValue::ConstInt(0)));
instrs.push(IRInstr::Goto(final_exit));
instrs.push(IRInstr::Label(final_exit));
}
return Some((instrs, Some(dest_var))); return Some((instrs, Some(dest_var)));
} else { } else {
if op.is_cmp() { if op.is_cmp() {
@@ -713,12 +771,13 @@ impl<'a> Generator<'a> {
let mut arg_vars = vec![]; let mut arg_vars = vec![];
let func_def = self.ir_function(func_id); let func_def = self.ir_function(func_id);
for arg in args.into_iter() { for (arg, param_type) in args.into_iter().zip(func_def.parameter_types.iter()) {
self.current_exit_label.push(None); self.current_exit_label.push(None);
let (arg_instrs, arg_var) = self.generate_expr(arg)?; let (mut arg_instrs, arg_var) = self.generate_expr(arg)?;
self.current_exit_label.pop(); self.current_exit_label.pop();
let arg_var = self.coerce_value(&mut arg_instrs, arg_var.unwrap(), param_type);
instrs.extend(arg_instrs); instrs.extend(arg_instrs);
arg_vars.push(arg_var.unwrap()); arg_vars.push(arg_var);
} }
let ret_variable = if matches!(func_def.return_type, IRType::Void) { let ret_variable = if matches!(func_def.return_type, IRType::Void) {
None None
@@ -730,10 +789,15 @@ impl<'a> Generator<'a> {
} }
}; };
if let Some((true_exit, false_exit)) = self.current_exit_label.last().cloned().flatten() { if let Some((true_exit, false_exit)) = self.current_exit_label.last().cloned().flatten() {
let var = var.clone().unwrap();
if matches!(var.data_type, IRType::Array(_, _) | IRType::Ptr(_)) {
instrs.push(IRInstr::Goto(true_exit));
} else {
let cmp_var = self.var_manager.declare_temp(IRType::I1); let cmp_var = self.var_manager.declare_temp(IRType::I1);
instrs.push(IRInstr::Cmp(cmp_var.clone(), VariableOrIntLit::Var(var.clone().unwrap()), CmpOp::Ne, VariableOrIntLit::IntLit(0))); instrs.push(IRInstr::Cmp(cmp_var.clone(), VariableOrIntLit::Var(var.clone()), CmpOp::Ne, VariableOrIntLit::IntLit(0)));
instrs.push(IRInstr::CondGoto(cmp_var, true_exit, false_exit)); instrs.push(IRInstr::CondGoto(cmp_var, true_exit, false_exit));
Some((instrs, var)) }
Some((instrs, Some(var)))
} else { } else {
Some((instrs, var)) Some((instrs, var))
} }
@@ -777,12 +841,13 @@ impl<'a> Generator<'a> {
let (index_instrs, index_var) = self.generate_expr(index)?; let (index_instrs, index_var) = self.generate_expr(index)?;
self.current_exit_label.pop(); self.current_exit_label.pop();
instrs.extend(index_instrs); instrs.extend(index_instrs);
let index_var = self.coerce_value(&mut instrs, index_var.unwrap(), &IRType::I32);
let addr_ty = IRType::Ptr(Box::new(elem_ty.into())); let addr_ty = IRType::Ptr(Box::new(elem_ty.into()));
let dest = self.var_manager.declare_temp(addr_ty); let dest = self.var_manager.declare_temp(addr_ty);
let elem_size_var = self.var_manager.declare_temp(IRType::I32); let elem_size_var = self.var_manager.declare_temp(IRType::I32);
let offset = self.var_manager.declare_temp(IRType::I32); let offset = self.var_manager.declare_temp(IRType::I32);
instrs.push(IRInstr::Move(elem_size_var.clone(), MoveRValue::ConstInt(elem_size as i32))); instrs.push(IRInstr::Move(elem_size_var.clone(), MoveRValue::ConstInt(elem_size as i32)));
instrs.push(IRInstr::Binary(offset.clone(), index_var.unwrap(), AstBinaryOp::Mul.into(), elem_size_var)); instrs.push(IRInstr::Binary(offset.clone(), index_var, AstBinaryOp::Mul.into(), elem_size_var));
instrs.push(IRInstr::Binary(dest.clone(), base, AstBinaryOp::Add.into(), offset)); instrs.push(IRInstr::Binary(dest.clone(), base, AstBinaryOp::Add.into(), offset));
Some((instrs, dest)) Some((instrs, dest))
} }
+3 -2
View File
@@ -124,10 +124,11 @@ impl IRType {
} }
pub fn get_elevate_result(lhs: &IRType, rhs: &IRType) -> Option<IRType> { pub fn get_elevate_result(lhs: &IRType, rhs: &IRType) -> Option<IRType> {
if matches!((lhs, rhs), (IRType::I32 | IRType::I1, IRType::I32 | IRType::I1)) {
return Some(IRType::I32);
}
if lhs == rhs { if lhs == rhs {
Some(lhs.clone()) Some(lhs.clone())
} else if (*lhs == IRType::I32 && *rhs == IRType::I1) || (*lhs == IRType::I1 && *rhs == IRType::I32) {
Some(IRType::I32)
} else { } else {
None None
} }
+2 -2
View File
@@ -34,8 +34,8 @@ pub enum SemaError {
ReturnExpressionOnVoidFunction, ReturnExpressionOnVoidFunction,
#[error("array dimension must be a positive integer literal")] #[error("array dimension must be a positive integer literal")]
InvalidArrayDimension, InvalidArrayDimension,
#[error("subscripted value is not an array or pointer")] #[error("subscripted value of type `{0}` is not an array or pointer")]
NotSubscriptable, NotSubscriptable(SemaType),
#[error("initializer element is not constant")] #[error("initializer element is not constant")]
InitializerNotConstant, InitializerNotConstant,
} }
+3 -2
View File
@@ -13,10 +13,11 @@ pub enum SemaType {
impl SemaType { impl SemaType {
pub fn get_elevate_result(lhs: &SemaType, rhs: &SemaType) -> Option<SemaType> { pub fn get_elevate_result(lhs: &SemaType, rhs: &SemaType) -> Option<SemaType> {
if matches!((lhs, rhs), (SemaType::I32 | SemaType::I1, SemaType::I32 | SemaType::I1)) {
return Some(SemaType::I32);
}
if lhs == rhs { if lhs == rhs {
Some(lhs.clone()) Some(lhs.clone())
} else if (*lhs == SemaType::I32 && *rhs == SemaType::I1) || (*lhs == SemaType::I1 && *rhs == SemaType::I32) {
Some(SemaType::I32)
} else { } else {
None None
} }