diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index ce8f2439d..0b05fdae2 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -3138,6 +3138,13 @@ static void decl_const(int vclass) needtoken(tTERM); } +static void check_struct_name(const char *name) +{ + LayoutSpec spec = deduce_layout_spec_by_name(name); + if (!can_redef_layout_spec(spec, Layout_PawnStruct)) + error(110, name, layout_spec_name(spec)); +} + /* * declstruct - declare a struct type */ @@ -3148,6 +3155,7 @@ static void declstruct(void) int tok; pstruct_t *pstruct; int size; + LayoutSpec spec; /* get the explicit tag (required!) */ tok = lex(&val,&str); @@ -3156,10 +3164,7 @@ static void declstruct(void) error(93); } - if (pstructs_find(str) != NULL) - { - error(98); - } + check_struct_name(str); pstruct = pstructs_add(str); @@ -3246,8 +3251,9 @@ static void declstruct(void) */ static void domethodmap() { - int val; char *str; + LayoutSpec spec; + int val, extends; char mapname[sNAMEMAX + 1]; methodmap_t *map; methodmap_t *parent = NULL; @@ -3261,11 +3267,11 @@ static void domethodmap() if (!isupper(*mapname)) error(109, decltype); - int maptag = pc_addtag(mapname); - if (methodmap_find_by_tag(maptag)) - error(103, decltype, mapname); + spec = deduce_layout_spec_by_name(mapname); + if (!can_redef_layout_spec(spec, Layout_MethodMap)) + error(110, mapname, layout_spec_name(spec)); - int extends = matchtoken('<'); + extends = matchtoken('<'); if (extends) { if (lex(&val, &str) != tSYMBOL) { error(93); @@ -3279,7 +3285,8 @@ static void domethodmap() map = (methodmap_t *)calloc(1, sizeof(methodmap_t)); map->parent = parent; - map->tag = maptag; + map->tag = pc_addtag(mapname); + map->spec = Layout_MethodMap; strcpy(map->name, mapname); methodmap_add(map); @@ -3597,15 +3604,17 @@ static void decl_enum(int vclass) cell increment,multiplier; constvalue *enumroot; symbol *enumsym; + LayoutSpec spec; /* get an explicit tag, if any (we need to remember whether an explicit * tag was passed, even if that explicit tag was "_:", so we cannot call * pc_addtag() here */ if (lex(&val,&str)==tLABEL) { - tag=pc_addtag(str); - if (methodmap_find_by_tag(tag)) - error(110, str, "methodmap"); + tag = pc_addtag(str); + spec = deduce_layout_spec_by_tag(tag); + if (!can_redef_layout_spec(spec, Layout_Enum)) + error(110, str, layout_spec_name(spec)); explicittag=TRUE; } else { lexpush(); @@ -3618,11 +3627,13 @@ static void decl_enum(int vclass) strcpy(enumname,str); /* save enum name (last constant) */ if (!explicittag) { tag=pc_addtag(enumname); - if (methodmap_find_by_tag(tag)) - error(110, str, "methodmap"); + spec = deduce_layout_spec_by_tag(tag); + if (!can_redef_layout_spec(spec, Layout_Enum)) + error(110, enumname, layout_spec_name(spec)); } else { - if (methodmap_find_by_name(enumname)) - error(110, str, "methodmap"); + spec = deduce_layout_spec_by_name(enumname); + if (!can_redef_layout_spec(spec, Layout_Enum)) + error(110, enumname, layout_spec_name(spec)); } } else { lexpush(); /* analyze again */ diff --git a/sourcepawn/compiler/sc5.scp b/sourcepawn/compiler/sc5.scp index bdbefbd20..65e5b743a 100644 --- a/sourcepawn/compiler/sc5.scp +++ b/sourcepawn/compiler/sc5.scp @@ -141,12 +141,12 @@ static char *errmsg[] = { /*095*/ "cannot have required parameters after optional parameters\n", /*096*/ "could not find member \"%s\" in struct \"%s\"\n", /*097*/ "symbol \"%s\" does not have a matching type\n", -/*098*/ "struct requires unique struct name\n", +/*098*/ "UNUSED\n", /*099*/ "member \"%s\" appears more than once in struct \"%s\"\n", /*100*/ "function prototypes do not match\n", /*101*/ "specify either all dimensions or only the last dimension\n", /*102*/ "cannot find %s %s\n", -/*103*/ "%s %s was already defined\n", +/*103*/ "UNUSED\n", /*104*/ "cannot find any methods for %s\n", /*105*/ "cannot find method %s.%s\n", /*106*/ "cannot call methods on an array\n", diff --git a/sourcepawn/compiler/sctracker.c b/sourcepawn/compiler/sctracker.c index e16c15a24..a4eeba968 100644 --- a/sourcepawn/compiler/sctracker.c +++ b/sourcepawn/compiler/sctracker.c @@ -484,3 +484,85 @@ void methodmaps_free() methodmap_first = NULL; methodmap_last = NULL; } + +LayoutSpec deduce_layout_spec_by_tag(int tag) +{ + symbol *sym; + const char *name; + methodmap_t *map; + if ((map = methodmap_find_by_tag(tag)) != NULL) + return map->spec; + if (tag & FUNCTAG) + return Layout_FuncTag; + + name = pc_tagname(tag); + if (pstructs_find(name)) + return Layout_PawnStruct; + if ((sym = findglb(name, sGLOBAL)) != NULL) + return Layout_Enum; + + return Layout_None; +} + +LayoutSpec deduce_layout_spec_by_name(const char *name) +{ + symbol *sym; + methodmap_t *map; + int tag = pc_findtag(name); + if (tag != -1 && (tag & FUNCTAG)) + return Layout_FuncTag; + if (pstructs_find(name)) + return Layout_PawnStruct; + if ((map = methodmap_find_by_name(name)) != NULL) + return map->spec; + if ((sym = findglb(name, sGLOBAL)) != NULL) + return Layout_Enum; + + return Layout_None; +} + +const char *layout_spec_name(LayoutSpec spec) +{ + switch (spec) { + case Layout_None: + return ""; + case Layout_Enum: + return "enum"; + case Layout_FuncTag: + return "functag"; + case Layout_PawnStruct: + return "deprecated-struct"; + case Layout_MethodMap: + return "methodmap"; + case Layout_Class: + return "class"; + } + return ""; +} + +int can_redef_layout_spec(LayoutSpec def1, LayoutSpec def2) +{ + // Normalize the ordering, since these checks are symmetrical. + if (def1 > def2) { + LayoutSpec temp = def2; + def2 = def1; + def1 = temp; + } + + switch (def1) { + case Layout_None: + return TRUE; + case Layout_Enum: + if (def2 == Layout_Enum || def2 == Layout_FuncTag) + return TRUE; + return def2 == Layout_MethodMap; + case Layout_FuncTag: + return def2 == Layout_Enum || def2 == Layout_FuncTag; + case Layout_PawnStruct: + case Layout_MethodMap: + return FALSE; + case Layout_Class: + return FALSE; + } + return FALSE; +} diff --git a/sourcepawn/compiler/sctracker.h b/sourcepawn/compiler/sctracker.h index c59d5102d..119269175 100644 --- a/sourcepawn/compiler/sctracker.h +++ b/sourcepawn/compiler/sctracker.h @@ -67,6 +67,18 @@ typedef struct pstruct_s struct pstruct_s *next; } pstruct_t; +// The ordering of these definitions should be preserved for +// can_redef_layout_spec(). +typedef enum +{ + Layout_None, + Layout_Enum, + Layout_FuncTag, + Layout_PawnStruct, + Layout_MethodMap, + Layout_Class +} LayoutSpec; + typedef struct methodmap_method_s { char name[sNAMEMAX+1]; @@ -78,6 +90,7 @@ typedef struct methodmap_s struct methodmap_s *next; struct methodmap_s *parent; int tag; + LayoutSpec spec; char name[sNAMEMAX+1]; methodmap_method_t **methods; size_t nummethods; @@ -100,6 +113,14 @@ funcenum_t *funcenums_add(const char *name); funcenum_t *funcenums_find_byval(int value); functag_t *functags_add(funcenum_t *en, functag_t *src); +/** + * Given a name or tag, find any extra weirdness it has associated with it. + */ +LayoutSpec deduce_layout_spec_by_tag(int tag); +LayoutSpec deduce_layout_spec_by_name(const char *name); +const char *layout_spec_name(LayoutSpec spec); +int can_redef_layout_spec(LayoutSpec olddef, LayoutSpec newdef); + /** * Heap functions */ diff --git a/sourcepawn/compiler/tests/fail-redef-methodmap-as-enum.sp b/sourcepawn/compiler/tests/fail-redef-methodmap-as-enum.sp deleted file mode 100644 index a383a9818..000000000 --- a/sourcepawn/compiler/tests/fail-redef-methodmap-as-enum.sp +++ /dev/null @@ -1,15 +0,0 @@ -native CloseHandle(Handle:this); - -methodmap Handle { - Close = CloseHandle; -}; - -methodmap Crab { -}; - -enum Crab { -}; - -public main() -{ -}