Skip to content

Commit

Permalink
improved error messages for function-definitions
Browse files Browse the repository at this point in the history
  • Loading branch information
PhilippRados committed Apr 22, 2024
1 parent 04e0812 commit 047a8ae
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 39 deletions.
4 changes: 2 additions & 2 deletions tests/snapshots/success_func_arr_return
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error: functions cannot return type 'int [2]'
| --> in tests/fixtures/func_arr_return.c:3:9
| --> in tests/fixtures/func_arr_return.c:3:5
|
3 arr some() {
| ^
| ^
error: functions cannot return type 'int [2]'
| --> in tests/fixtures/func_arr_return.c:10:8
|
Expand Down
15 changes: 1 addition & 14 deletions wrecc_compiler/src/compiler/typechecker/mir/decl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,20 +149,8 @@ impl Function {
}
Ok(())
}
pub fn main_return(&mut self, token: &Token, body: &mut Vec<Stmt>) -> Result<(), Error> {
pub fn implicit_main_return(&mut self, body: &mut Vec<Stmt>) {
if self.name == "main" {
if self.return_type != Type::Primitive(Primitive::Int) {
return Err(Error::new(
token,
ErrorKind::InvalidMainReturn(self.return_type.clone()),
));
}
if self.is_inline {
return Err(Error::new(
token,
ErrorKind::Regular("'main' function cannot be declared 'inline'"),
));
}
if !self.returns_all_paths {
self.returns_all_paths = true;

Expand All @@ -173,7 +161,6 @@ impl Function {
})));
}
}
Ok(())
}
}

Expand Down
88 changes: 65 additions & 23 deletions wrecc_compiler/src/compiler/typechecker/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -964,7 +964,25 @@ impl TypeChecker {
})?;

if return_type.is_func() || return_type.is_array() {
return Err(Error::new(&token, ErrorKind::InvalidReturnType(return_type)));
return Err(Error::new(
&func_decl.name,
ErrorKind::InvalidReturnType(return_type),
));
}

if name_string == "main" {
if return_type != Type::Primitive(Primitive::Int) {
return Err(Error::new(
&func_decl.name,
ErrorKind::InvalidMainReturn(return_type),
));
}
if func_decl.is_inline {
return Err(Error::new(
&func_decl.name,
ErrorKind::Regular("'main' function cannot be declared 'inline'"),
));
}
}

// have to push scope before declaring local variables
Expand Down Expand Up @@ -1010,27 +1028,35 @@ impl TypeChecker {
return Err(Error::new(&func_decl.name, ErrorKind::UnnamedFuncParams));
}
}
let mut errors = Vec::new();
let mut func_body = Vec::new();

// check function body
let body = self.block(&mut func, body);

func.compare_gotos()?;
match self.block(&mut func, body) {
Ok(mir::stmt::Stmt::Block(stmts)) => func_body = stmts,
Err(Error { kind: ErrorKind::Multiple(errs), .. }) => {
errors = errs;
}
_ => unreachable!(),
};

let mir::stmt::Stmt::Block(mut body) = body? else {unreachable!()};
if let Err(e) = func.compare_gotos() {
errors.push(e);
}

func.main_return(&func_decl.name, &mut body)?;
func.implicit_main_return(&mut func_body);

if !func.return_type.is_void() && !func.returns_all_paths {
if errors.is_empty() {
if !func.return_type.is_void() && !func.returns_all_paths {
return Err(Error::new(
&func_decl.name,
ErrorKind::NoReturnAllPaths(name_string),
));
}
func.returns_all_paths = false;

Err(Error::new(
&func_decl.name,
ErrorKind::NoReturnAllPaths(name_string),
))
Ok(mir::decl::ExternalDeclaration::Function(func, symbol, func_body))
} else {
func.returns_all_paths = false;

Ok(mir::decl::ExternalDeclaration::Function(func, symbol, body))
Err(Error::new_multiple(errors))
}
}
fn visit_stmt(
Expand Down Expand Up @@ -2970,22 +2996,20 @@ int main(){
inline static foo();
inline int bar;
void some(){
int main() {
extern inline char goo(inline some);
inline char zoo();
char zoo();
typedef inline boo(void);
}
int inline main() {}
",
)
.unwrap_err();

assert!(matches!(
dbg!(actual.as_slice()),
actual.as_slice(),
&[
Error {
kind: ErrorKind::Regular(..),
Expand All @@ -3001,10 +3025,28 @@ int inline main() {}
kind: ErrorKind::Regular("'inline' not allowed with 'typedef' storage-class"),
..
},
Error {
kind: ErrorKind::Regular("'main' function cannot be declared 'inline'"),
..
},
]
));
}
#[test]
fn missing_goto() {
let actual = typecheck(
"
int foo(){
char c = &1;
goto b;
int *p = c;
}
",
)
.unwrap_err();

assert!(matches!(
actual.as_slice(),
&[
Error { kind: ErrorKind::NotLvalue(..), .. },
Error { kind: ErrorKind::IllegalAssign(..), .. },
Error { kind: ErrorKind::UndeclaredLabel(..), .. },
]
));
}
Expand Down

0 comments on commit 047a8ae

Please sign in to comment.