diff --git a/cobj/cobj.c b/cobj/cobj.c index b86d65b7..85599ac2 100644 --- a/cobj/cobj.c +++ b/cobj/cobj.c @@ -1779,6 +1779,14 @@ static int process_translate(struct filename *fn) { if (ret) { return ret; } + + /* Validate duplicate labels in the same section */ + for (q = current_program; q; q = q->next_program) { + if (cb_validate_labels(q)) { + return -1; + } + } + if (cb_flag_syntax_only || current_program->entry_list == NULL) { return 0; } diff --git a/cobj/tree.h b/cobj/tree.h index c652cd63..b6dca12e 100644 --- a/cobj/tree.h +++ b/cobj/tree.h @@ -1500,6 +1500,7 @@ extern void cb_validate_program_environment(struct cb_program *prog); extern void cb_validate_program_data(struct cb_program *prog); extern void cb_validate_program_body(struct cb_program *prog); extern void cb_validate_indexed_file_key(const struct cb_file *f); +extern int cb_validate_labels(struct cb_program *prog); extern cb_tree cb_build_expr(cb_tree list); extern cb_tree cb_build_cond(cb_tree x); diff --git a/cobj/typeck.c b/cobj/typeck.c index 2bd1300a..4bc08334 100644 --- a/cobj/typeck.c +++ b/cobj/typeck.c @@ -1483,6 +1483,51 @@ void cb_validate_program_body(struct cb_program *prog) { } } +int cb_validate_labels(struct cb_program *prog) { + cb_tree l1, l2; + int duplicate_count = 0; + + for (l1 = prog->exec_list; l1; l1 = CB_CHAIN(l1)) { + cb_tree x1 = CB_VALUE(l1); + if (!CB_LABEL_P(x1)) { + continue; + } + struct cb_label *label1 = CB_LABEL(x1); + if (label1->is_section) { + continue; + } + + for (l2 = CB_CHAIN(l1); l2; l2 = CB_CHAIN(l2)) { + cb_tree x2 = CB_VALUE(l2); + if (!CB_LABEL_P(x2)) { + continue; + } + struct cb_label *label2 = CB_LABEL(x2); + if (label2->is_section) { + break; + } + + if (label1->section != label2->section) { + break; + } + + if (strcmp((const char *)label1->name, (const char *)label2->name) == 0) { + if (!label2->section || !label2->section->name || + strcmp((char *)label2->section->name, "MAIN SECTION") == 0) { + cb_error_x(x2, _("Duplicate paragraph '%s' in the default section"), + label2->name); + } else { + cb_error_x(x2, _("Duplicate paragraph '%s' in section '%s'"), + label2->name, label2->section->name); + } + cb_error_x(x1, _("'%s' previously defined here"), label1->name); + duplicate_count++; + } + } + } + return duplicate_count; +} + /* * Expressions */ diff --git a/tests/syntax.src/definition.at b/tests/syntax.src/definition.at index 193787f7..14cf4ba6 100644 --- a/tests/syntax.src/definition.at +++ b/tests/syntax.src/definition.at @@ -501,24 +501,85 @@ AT_CLEANUP AT_SETUP([Redefinition of paragraph names]) -AT_DATA([prog.cob], [ +AT_DATA([prog1.cob], [ IDENTIFICATION DIVISION. - PROGRAM-ID. prog. + PROGRAM-ID. prog1. PROCEDURE DIVISION. + *No Label L. + *No Label L. STOP RUN. ]) -AT_CHECK([${COMPILE_ONLY} prog.cob], [0], , -[]) - -## Change when we DON'T allow this -## AT_CHECK([${COMPILE_ONLY} prog.cob], [1], , -## [prog.cob: In paragraph 'L': -## prog.cob:6: Error: redefinition of 'L' -## prog.cob:5: Error: 'L' previously defined here -## ]) +AT_DATA([prog2.cob], [ + IDENTIFICATION DIVISION. + PROGRAM-ID. prog2. + PROCEDURE DIVISION. + SECTION-A SECTION. + L. + *No Label + L. + STOP RUN. +]) + +AT_DATA([prog3.cob], [ + IDENTIFICATION DIVISION. + PROGRAM-ID. prog3. + PROCEDURE DIVISION. + SECTION-A SECTION. + L. + SECTION-B SECTION. + L. + STOP RUN. +]) + +AT_CHECK([${COMPILE} -fsyntax-only prog1.cob], [1], , +[prog1.cob:8: Error: Duplicate paragraph 'L' in the default section +prog1.cob:6: Error: 'L' previously defined here +]) +AT_CHECK([${COMPILE} -fsyntax-only prog2.cob], [1], , +[prog2.cob:8: Error: Duplicate paragraph 'L' in section 'SECTION-A' +prog2.cob:6: Error: 'L' previously defined here +]) +AT_CHECK([${COMPILE} -fsyntax-only prog3.cob]) + +AT_CHECK([${COMPILE} prog1.cob], [1], , +[prog1.cob:8: Error: Duplicate paragraph 'L' in the default section +prog1.cob:6: Error: 'L' previously defined here +]) +AT_CHECK([${COMPILE} prog2.cob], [1], , +[prog2.cob:8: Error: Duplicate paragraph 'L' in section 'SECTION-A' +prog2.cob:6: Error: 'L' previously defined here +]) +AT_CHECK([${COMPILE} prog3.cob]) + +AT_CHECK([${COMPILE} prog1.cob prog3.cob], [1], , +[prog1.cob:8: Error: Duplicate paragraph 'L' in the default section +prog1.cob:6: Error: 'L' previously defined here +]) +AT_CHECK([${COMPILE} prog2.cob prog3.cob], [1], , +[prog2.cob:8: Error: Duplicate paragraph 'L' in section 'SECTION-A' +prog2.cob:6: Error: 'L' previously defined here +]) + +AT_CHECK([${COMPILE} prog3.cob prog1.cob], [1], , +[prog1.cob:8: Error: Duplicate paragraph 'L' in the default section +prog1.cob:6: Error: 'L' previously defined here +]) +AT_CHECK([${COMPILE} prog3.cob prog2.cob], [1], , +[prog2.cob:8: Error: Duplicate paragraph 'L' in section 'SECTION-A' +prog2.cob:6: Error: 'L' previously defined here +]) + +AT_CHECK([${COMPILE} prog1.cob prog2.cob], [1], , +[prog1.cob:8: Error: Duplicate paragraph 'L' in the default section +prog1.cob:6: Error: 'L' previously defined here +]) +AT_CHECK([${COMPILE} prog2.cob prog1.cob], [1], , +[prog2.cob:8: Error: Duplicate paragraph 'L' in section 'SECTION-A' +prog2.cob:6: Error: 'L' previously defined here +]) AT_CLEANUP