From 1fbb59c03c03b7a63fbd5e8ce084e34b3ecaf9f6 Mon Sep 17 00:00:00 2001
From: "ben.franksen" <ben.franksen@online.de>
Date: Tue, 12 Apr 2011 16:00:24 +0000
Subject: [PATCH] snc,test: reject badly scoped assign/monitor/sync/syncq

Also added a test for this and removed item from TODO list.
---
 TODO                   |  5 -----
 src/snc/analysis.c     | 35 +++++++++++++++++++++++++++++++----
 test/validate/Makefile |  2 ++
 test/validate/scope.st | 20 ++++++++++++++++++++
 test/validate/syncq.st |  2 +-
 5 files changed, 54 insertions(+), 10 deletions(-)
 create mode 100644 test/validate/scope.st

diff --git a/TODO b/TODO
index eb1ade6e..7ba4a114 100644
--- a/TODO
+++ b/TODO
@@ -47,8 +47,3 @@
   has been connected to separate PVs. Currently this puts/gets the first element,
   but wouldn't it be nice if it meant to put/get all (connected) elements?
   Write to tech-talk and ask (since it breaks compatibility)?
-
-* What if a variable is declared in a outer scope (e.g. global), but
-  the "monitor" or "sync" appears in an inner scope? The compiler currently
-  allows this but there is no well-defined semantics I can think of.
-  Need to fix the compiler to abort with an error in this case.
diff --git a/src/snc/analysis.c b/src/snc/analysis.c
index f6151137..91831d61 100644
--- a/src/snc/analysis.c
+++ b/src/snc/analysis.c
@@ -306,13 +306,20 @@ static void analyse_assign(SymTable st, ChanList *chan_list, Expr *scope, Expr *
 	assert(defn->type == D_ASSIGN);
 	if (!vp)
 	{
-		error_at_expr(defn, "variable '%s' not declared\n", name);
+		error_at_expr(defn, "cannot assign variable '%s': "
+			"variable was not declared\n", name);
 		return;
 	}
 	assert(vp->type);
 	if (!type_assignable(vp->type))
 	{
-		error_at_expr(defn, "this type of variable cannot be assigned to a pv\n", name);
+		error_at_expr(defn, "cannot assign variable '%s': wrong type\n", name);
+		return;
+	}
+	if (vp->scope != scope)
+	{
+		error_at_expr(defn, "cannot assign variable '%s': "
+			"assign must be in the same scope as declaration\n", name);
 		return;
 	}
 	if (defn->assign_subscr)
@@ -497,7 +504,7 @@ static void monitor_var(Expr *defn, Var *vp)
 
 	if (vp->assign == M_NONE)
 	{
-		error_at_expr(defn, "variable '%s' not assigned\n", vp->name);
+		error_at_expr(defn, "cannot monitor variable '%s': not assigned\n", vp->name);
 		return;
 	}
 	if (vp->monitor == M_SINGLE)
@@ -596,7 +603,13 @@ static void analyse_monitor(SymTable st, Expr *scope, Expr *defn)
 	if (!vp)
 	{
 		error_at_expr(defn,
-			"variable '%s' not declared\n", var_name);
+			"cannot monitor variable '%s': not declared\n", var_name);
+		return;
+	}
+	if (vp->scope != scope)
+	{
+		error_at_expr(defn, "cannot monitor variable '%s': "
+			"monitor must be in the same scope as declaration\n", var_name);
 		return;
 	}
 	if (defn->monitor_subscr)
@@ -737,6 +750,13 @@ static void analyse_sync(SymTable st, Expr *scope, Expr *defn)
 		error_at_expr(defn, "variable '%s' not declared\n", var_name);
 		return;
 	}
+	if (vp->scope != scope)
+	{
+		error_at_expr(defn, "cannot sync variable '%s' to event flag '%s': "
+			"sync must be in the same scope as (variable) declaration\n",
+			var_name, ef_name);
+		return;
+	}
 	if (vp->sync == M_SINGLE)
 	{
 		error_at_expr(defn, "variable '%s' already sync'd\n", vp->name);
@@ -893,6 +913,13 @@ static void analyse_syncq(SymTable st, SyncQList *syncq_list, Expr *scope, Expr
 		error_at_expr(defn, "variable '%s' not declared\n", var_name);
 		return;
 	}
+	if (vp->scope != scope)
+	{
+		error_at_expr(defn, "cannot syncq variable '%s' to event flag '%s': "
+			"sync must be in the same scope as (variable) declaration\n",
+			var_name, ef_name);
+		return;
+	}
 	if (vp->syncq == M_SINGLE)
 	{
 		error_at_expr(defn, "variable '%s' already syncq'd\n", vp->name);
diff --git a/test/validate/Makefile b/test/validate/Makefile
index 72d298cc..d2897520 100644
--- a/test/validate/Makefile
+++ b/test/validate/Makefile
@@ -15,6 +15,8 @@ TESTPROD += declarations
 TESTPROD += local
 TESTPROD += pvPutAsync
 TESTPROD += pvSync
+#compiler test, should fail with errors
+#TESTPROD += scope
 TESTPROD += sncDelay
 TESTPROD += sncEntry
 TESTPROD += sncEntryOpte
diff --git a/test/validate/scope.st b/test/validate/scope.st
new file mode 100644
index 00000000..ac4e8b9b
--- /dev/null
+++ b/test/validate/scope.st
@@ -0,0 +1,20 @@
+program scope
+
+int i, j;
+evflag f, g, h;
+
+ss start {
+    assign i;
+    monitor i;
+    sync i to f;
+    syncq i to f;
+    int k;
+    state first {
+        assign j;
+        monitor j;
+        sync j to g;
+        syncq k to h;
+        when () {
+        } exit
+    }
+}
diff --git a/test/validate/syncq.st b/test/validate/syncq.st
index 4147db6d..b7ccafba 100644
--- a/test/validate/syncq.st
+++ b/test/validate/syncq.st
@@ -23,6 +23,7 @@ syncq x to ef_x;
 
 int n = 0;
 assign n;
+monitor n;
 
 ss get {
     state get {
@@ -62,7 +63,6 @@ ss put {
 }
 
 ss flush {
-    monitor n;
     state idle {
         when (n%20==0) {
             printf("flush\n");
-- 
GitLab