scc

simple c99 compiler
git clone git://git.simple-cc.org/scc
Log | Files | Refs | Submodules | README | LICENSE

commit a30f8e9edfde16e4d231503214333ff340f24b29
parent ac8455c287b0178649255acd37a63e938ef36d75
Author: Michael Forney <mforney@mforney.org>
Date:   Mon, 13 Feb 2017 11:28:26 -0800

Fix namespace for previously declared nested struct identifier

In structdcl, newtag is called which looks up the struct identifier in
NS_TAG, then sets namespace to NS_IDEN and reads the next token.

This is incorrect since if the struct was already declared, the next
token is an identifier, which is looked up in the wrong namespace.

This causes the following to be incorrectly rejected

	struct S1 { int x; };
	struct S2 { struct S1 s1; };
	struct S2 s2;
	s2.s1.x = 1;

and this to be incorrectly accepted

	struct S1 { int x; };
	struct S2 { struct S1 s1; };
	s1.x = 1;

To resolve this, make newtag preserve namespace. This also allows slight
simplification of structdcl.

Diffstat:
Mcc1/decl.c | 20++++++++++----------
Atests/execute/0109-struct.c | 10++++++++++
Mtests/execute/scc-tests.lst | 1+
3 files changed, 21 insertions(+), 10 deletions(-)

diff --git a/cc1/decl.c b/cc1/decl.c @@ -467,11 +467,13 @@ static Symbol * newtag(void) { Symbol *sym; - int op, tag = yylval.token; - static unsigned ns = NS_STRUCTS; + int ns, op, tag = yylval.token; + static unsigned tpns = NS_STRUCTS; + ns = namespace; namespace = NS_TAG; next(); + namespace = ns; switch (yytoken) { case IDEN: @@ -479,7 +481,6 @@ newtag(void) sym = yylval.sym; if ((sym->flags & SDECLARED) == 0) install(NS_TAG, yylval.sym); - namespace = NS_IDEN; next(); break; default: @@ -489,10 +490,10 @@ newtag(void) if (!sym->type) { Type *tp; - if (ns == NS_STRUCTS + NR_MAXSTRUCTS) + if (tpns == NS_STRUCTS + NR_MAXSTRUCTS) error("too many tags declared"); tp = mktype(NULL, tag, 0, NULL); - tp->ns = ns++; + tp->ns = tpns++; sym->type = tp; tp->tag = sym; DBG("declared tag '%s' with ns = %d\n", @@ -514,15 +515,14 @@ structdcl(void) static int nested; int ns; - ns = namespace; sym = newtag(); tp = sym->type; - namespace = tp->ns; - if (!accept('{')) { - namespace = ns; + if (!accept('{')) return tp; - } + + ns = namespace; + namespace = tp->ns; if (tp->prop & TDEFINED && sym->ctx == curctx) error("redefinition of struct/union '%s'", sym->name); diff --git a/tests/execute/0109-struct.c b/tests/execute/0109-struct.c @@ -0,0 +1,10 @@ +struct S1 { int x; }; +struct S2 { struct S1 s1; }; + +int +main() +{ + struct S2 s2; + s2.s1.x = 1; + return 0; +} diff --git a/tests/execute/scc-tests.lst b/tests/execute/scc-tests.lst @@ -99,3 +99,4 @@ 0106-ppcast.c 0107-bnot.c 0108-bug.c +0109-struct.c