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);
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![];
loop {
@@ -328,6 +334,30 @@ impl Parser {
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(
&mut self,
init_declarator: InitDeclarator,
+4
View File
@@ -59,6 +59,10 @@ impl Parser {
}
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) {
Ok(var_decl) => return Ok(Statement::VarDecl(var_decl)),
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 {
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,
None => {
self.current_exit_label.pop();
@@ -93,8 +93,9 @@ impl<'a> Generator<'a> {
};
self.current_exit_label.pop();
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.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)?;
match op {
AstUnaryOp::Add => Some(value),
AstUnaryOp::Sub => value.checked_neg(),
AstUnaryOp::Sub => Some(value.wrapping_neg()),
AstUnaryOp::Not => Some((value == 0) as i32),
}
}
HirExprValue::BinaryOp { lhs, op, rhs } => {
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)?;
match op {
AstBinaryOp::Add => lhs.checked_add(rhs),
AstBinaryOp::Sub => lhs.checked_sub(rhs),
AstBinaryOp::Mul => lhs.checked_mul(rhs),
AstBinaryOp::Div => lhs.checked_div(rhs),
AstBinaryOp::Mod => lhs.checked_rem(rhs),
AstBinaryOp::Add => Some(lhs.wrapping_add(rhs)),
AstBinaryOp::Sub => Some(lhs.wrapping_sub(rhs)),
AstBinaryOp::Mul => Some(lhs.wrapping_mul(rhs)),
AstBinaryOp::Div if rhs != 0 => Some(lhs.wrapping_div(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::NotEqual => Some((lhs != rhs) as i32),
AstBinaryOp::Less => Some((lhs < rhs) as i32),
@@ -214,7 +222,7 @@ impl<'a> Generator<'a> {
match return_stmt.value {
Some(expr) => {
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,
None => {
self.current_exit_label.pop();
@@ -222,8 +230,10 @@ impl<'a> Generator<'a> {
}
};
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.push(IRInstr::Move(func_exit.1.unwrap(), MoveRValue::Var(value_var.unwrap())));
instrs.push(IRInstr::Move(target, MoveRValue::Var(value_var)));
}
None => {},
}
@@ -387,6 +397,35 @@ impl<'a> Generator<'a> {
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>)> {
// there may be some expr that doesn't produce value, like void func call
let (mut instrs, var) = match expr.value {
@@ -414,6 +453,7 @@ impl<'a> Generator<'a> {
self.current_exit_label.push(None);
let (mut instrs, rvalue_var) = self.generate_expr(*rvalue)?;
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)?;
instrs.extend(lvalue_instrs);
if is_addr {
@@ -509,17 +549,22 @@ impl<'a> Generator<'a> {
let operand_var = operand_var.unwrap();
let dest_var = match op {
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)));
dest_var
},
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));
dest_var
},
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
if !parent_is_logical {
let exit = exit_passdown.unwrap(); // (false_exit, true_exit) (consider `not`)
@@ -626,9 +671,7 @@ impl<'a> Generator<'a> {
// do implicit convert if needed
// TODO: further check
if !op.is_logical() && convert_to != left_var.data_type {
let temp_var = self.var_manager.declare_temp(convert_to.clone());
instrs.push(IRInstr::Move(temp_var.clone(), MoveRValue::Var(left_var)));
left_var = temp_var;
left_var = self.coerce_value(&mut instrs, left_var, &convert_to);
}
let result_type;
match op {
@@ -640,7 +683,13 @@ impl<'a> Generator<'a> {
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 {
AstBinaryOp::And | AstBinaryOp::Or => {
instrs.push(IRInstr::Label(exit.unwrap().1));
@@ -666,9 +715,7 @@ impl<'a> Generator<'a> {
// true_exit:
instrs.extend(right_instrs);
if !op.is_logical() && convert_to != right_var.data_type {
let temp_var = self.var_manager.declare_temp(convert_to);
instrs.push(IRInstr::Move(temp_var.clone(), MoveRValue::Var(right_var)));
right_var = temp_var;
right_var = self.coerce_value(&mut instrs, right_var, &convert_to);
}
if !op.is_logical() {
if let Some((true_exit, false_exit)) = parent_exit {
@@ -684,6 +731,17 @@ impl<'a> Generator<'a> {
}
}
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)));
} else {
if op.is_cmp() {
@@ -713,12 +771,13 @@ impl<'a> Generator<'a> {
let mut arg_vars = vec![];
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);
let (arg_instrs, arg_var) = self.generate_expr(arg)?;
let (mut arg_instrs, arg_var) = self.generate_expr(arg)?;
self.current_exit_label.pop();
let arg_var = self.coerce_value(&mut arg_instrs, arg_var.unwrap(), param_type);
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) {
None
@@ -730,10 +789,15 @@ impl<'a> Generator<'a> {
}
};
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);
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));
Some((instrs, var))
}
Some((instrs, Some(var)))
} else {
Some((instrs, var))
}
@@ -777,12 +841,13 @@ impl<'a> Generator<'a> {
let (index_instrs, index_var) = self.generate_expr(index)?;
self.current_exit_label.pop();
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 dest = self.var_manager.declare_temp(addr_ty);
let elem_size_var = 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::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));
Some((instrs, dest))
}
+3 -2
View File
@@ -124,10 +124,11 @@ impl 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 {
Some(lhs.clone())
} else if (*lhs == IRType::I32 && *rhs == IRType::I1) || (*lhs == IRType::I1 && *rhs == IRType::I32) {
Some(IRType::I32)
} else {
None
}
+2 -2
View File
@@ -34,8 +34,8 @@ pub enum SemaError {
ReturnExpressionOnVoidFunction,
#[error("array dimension must be a positive integer literal")]
InvalidArrayDimension,
#[error("subscripted value is not an array or pointer")]
NotSubscriptable,
#[error("subscripted value of type `{0}` is not an array or pointer")]
NotSubscriptable(SemaType),
#[error("initializer element is not constant")]
InitializerNotConstant,
}
+3 -2
View File
@@ -13,10 +13,11 @@ pub enum SemaType {
impl 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 {
Some(lhs.clone())
} else if (*lhs == SemaType::I32 && *rhs == SemaType::I1) || (*lhs == SemaType::I1 && *rhs == SemaType::I32) {
Some(SemaType::I32)
} else {
None
}