diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass1Procedures.java b/src/main/java/dk/camelot64/kickc/passes/Pass1Procedures.java index f063ff711..63bd13316 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass1Procedures.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass1Procedures.java @@ -6,6 +6,8 @@ import dk.camelot64.kickc.model.Program; import dk.camelot64.kickc.model.statements.Statement; import dk.camelot64.kickc.model.statements.StatementCall; import dk.camelot64.kickc.model.symbols.Procedure; +import dk.camelot64.kickc.model.symbols.Scope; +import dk.camelot64.kickc.model.symbols.Symbol; /** * Updates procedure calls to point to the actual procedure called. @@ -23,10 +25,13 @@ public class Pass1Procedures extends Pass2SsaOptimization { if(statement instanceof StatementCall) { StatementCall call = (StatementCall) statement; String procedureName = call.getProcedureName(); - Procedure procedure = getScope().getLocalProcedure(procedureName); - if(procedure == null) { - throw new CompileError("Called procedure not found. " + call.toString(getProgram(), false), statement.getSource()); - } + Scope localScope = (Scope) getScope().getSymbol(block.getScope()); + final Symbol procedureSymbol = localScope.findSymbol(procedureName); + if(procedureSymbol == null) + throw new CompileError("Called procedure not found. " + procedureName, statement.getSource()); + if(!(procedureSymbol instanceof Procedure)) + throw new CompileError("Called symbol is not a procedure. " + procedureSymbol.toString(), statement.getSource()); + Procedure procedure = (Procedure) procedureSymbol; call.setProcedure(procedure.getRef()); if(procedure.isVariableLengthParameterList() && procedure.getParameters().size() > call.getParameters().size()) { throw new CompileError("Wrong number of parameters in call. Expected " + procedure.getParameters().size() + " or more. " + statement.toString(), statement.getSource()); diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index 7a71aa7ec..c47a86d03 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java @@ -42,6 +42,11 @@ public class TestPrograms { public TestPrograms() { } + @Test + public void testLocalVarShadowingProcedure() throws IOException, URISyntaxException { + assertError("local-var-shadowing-procedure.c", "Called symbol is not a procedure. main::doit"); + } + @Test public void testAdventOfCode04() throws IOException, URISyntaxException { compileAndCompare("adventofcode/2020-04.c"); diff --git a/src/test/kc/local-var-shadowing-procedure.c b/src/test/kc/local-var-shadowing-procedure.c new file mode 100644 index 000000000..6210a6065 --- /dev/null +++ b/src/test/kc/local-var-shadowing-procedure.c @@ -0,0 +1,12 @@ +// Demonstrate that local variable shadowing a global procedure causes an error + +void main() { + char doit = 7; + doit(); +} + +char * const SCREEN = 0x0400; + +void doit() { + SCREEN[0] = '*'; +} \ No newline at end of file