diff --git a/gcc/cobol/Make-lang.in b/gcc/cobol/Make-lang.in index 5f596ee1b8603704bdf563daf2f38f3823498f3a..8ef8215fbc4726f3823e4be5f0fd58793fb2f4aa 100644 --- a/gcc/cobol/Make-lang.in +++ b/gcc/cobol/Make-lang.in @@ -195,10 +195,12 @@ cobol/cdf.o: cobol/cdf.c \ $(srcdir)/cobol/cbldiag.h \ $(srcdir)/cobol/cdfval.h \ $(srcdir)/cobol/copybook.h \ + $(srcdir)/cobol/exceptg.h \ $(srcdir)/cobol/symbols.h \ $(srcdir)/cobol/util.h \ $(srcdir)/../libgcobol/common-defs.h \ - $(srcdir)/../libgcobol/ec.h + $(srcdir)/../libgcobol/ec.h \ + $(srcdir)/../libgcobol/exceptl.h cobol/parse.o: cobol/parse.c \ $(srcdir)/cobol/cbldiag.h \ @@ -231,6 +233,7 @@ cobol/scan.o: cobol/scan.c \ $(srcdir)/cobol/cobol-system.h \ $(srcdir)/cobol/copybook.h \ $(srcdir)/cobol/dts.h \ + $(srcdir)/cobol/exceptg.h \ $(srcdir)/cobol/inspect.h \ $(srcdir)/cobol/lexio.h \ $(srcdir)/cobol/scan_ante.h \ diff --git a/gcc/cobol/UAT/testsuite.src/fundamental.at b/gcc/cobol/UAT/testsuite.src/fundamental.at index ecec2858735715494694755efc7fd582b542dfa1..cf3eda52e5b555a5971dd6d0ad96bd4a699e1893 100644 --- a/gcc/cobol/UAT/testsuite.src/fundamental.at +++ b/gcc/cobol/UAT/testsuite.src/fundamental.at @@ -63,12 +63,9 @@ AT_DATA([prog.cob], [ DISPLAY "Gratuitous procedure division statement.". END PROGRAM prog. ]) -AT_CHECK([$COMPILE prog.cob], [1], [], [prog.cob:9:9: error: syntax error: name truncated to 'this-should-fail_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx6' (max 63 characters) +AT_CHECK([$COMPILE prog.cob], [1], [], [prog.cob:9:11: error: name truncated to 'this-should-fail_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx6' (max 63 characters) 9 | 77 this-should-fail_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx64 - | ^ -prog.cob:11:2: error: 1 errors in DATA DIVISION, compilation ceases - 11 | PROCEDURE DIVISION. - | ^ + | ^ cobol1: error: failed compiling prog.cob ]) AT_CLEANUP diff --git a/gcc/cobol/parse.y b/gcc/cobol/parse.y index 2f6105d14f5e41e85eb470d5a1e84101b4bfc755..fe0fb513fb918b5b5337e7cc08bc1bcc5774ef4e 100644 --- a/gcc/cobol/parse.y +++ b/gcc/cobol/parse.y @@ -1036,7 +1036,8 @@ program_id: PROGRAM_ID dot namestr[name] program_as program_attrs[attr] dot if( symbols_begin() == symbols_end() ) { symbol_table_init(); } - if( !current.new_program(LblProgram, name, $program_as.data, + if( !current.new_program(@name, LblProgram, name, + $program_as.data, $attr.common, $attr.initial) ) { auto L = symbol_program(current_program_index(), name); assert(L); @@ -1069,7 +1070,8 @@ function_id: FUNCTION '.' NAME program_as program_attrs[attr] '.' if( symbols_begin() == symbols_end() ) { symbol_table_init(); } - if( !current.new_program(LblFunction, $NAME, $program_as.data, + if( !current.new_program(@NAME, LblFunction, $NAME, + $program_as.data, $attr.common, $attr.initial) ) { auto L = symbol_program(current_program_index(), $NAME); assert(L); @@ -1377,7 +1379,7 @@ select: SELECT optional NAME[name] select_clauses[clauses] '.' file->optional = $optional; file->line = yylineno; - if( !namcpy(file->name, $name) ) YYERROR; + if( !namcpy(@clauses, file->name, $name) ) YYERROR; if( ! ($clauses.clauses & assign_clause_e) ) { error_msg(@name, "ASSIGN clause missing for %s", file->name); @@ -1450,7 +1452,7 @@ select: SELECT optional NAME[name] select_clauses[clauses] '.' file.optional = $optional; file.line = yylineno; - if( !namcpy(file.name, $name) ) YYERROR; + if( !namcpy(@name, file.name, $name) ) YYERROR; if( file_add(@name, &file) == NULL ) YYERROR; } @@ -1927,7 +1929,7 @@ repo_program: PROGRAM_kw NAME repo_as .attr = quoted_e, .parent = parent, .data = {.initial = $repo_as.data} }; - namcpy(prog.name, $NAME); + namcpy(@NAME, prog.name, $NAME); if( ! prog.data.initial ) { assert(program); prog.data.initial = program->name; @@ -1966,7 +1968,7 @@ special_name: dev_mnemonic { if( !$abc ) YYERROR; assert($abc); // already in symbol table - if( !namcpy($abc->name, $name) ) YYERROR; + if( !namcpy(@name, $abc->name, $name) ) YYERROR; if( yydebug ) $abc->dump(); } | CLASS NAME is domains @@ -1975,7 +1977,7 @@ special_name: dev_mnemonic FldClass, FldInvalid, 0, 0, 0, 0, nonarray, yylineno, "", 0, cbl_field_t::linkage_t(), { 0,0,0,0, NULL, NULL, { NULL }, { NULL } }, NULL }; - if( !namcpy(field.name, $2) ) YYERROR; + if( !namcpy(@NAME, field.name, $2) ) YYERROR; struct cbl_domain_t *domain = new cbl_domain_t[ domains.size() + 1 ] ; @@ -2035,7 +2037,7 @@ dev_mnemonic: device_name is NAME { cbl_special_name_t special = { .token = $1.token, .id = $1.id }; - if( !namcpy(special.name, $NAME) ) YYERROR; + if( !namcpy(@NAME, special.name, $NAME) ) YYERROR; const char *filename; @@ -2077,7 +2079,7 @@ dev_mnemonic: device_name is NAME } cbl_special_name_t special = { .id = p->second }; - if( !namcpy(special.name, $name) ) YYERROR; + if( !namcpy(@name, special.name, $name) ) YYERROR; symbol_special_add(PROGRAM, &special); } @@ -2841,7 +2843,7 @@ index_field1: ctx_name[name] cbl_field_t field = { .type = FldIndex, .parent = field_index(current_field()), .data = data }; - if( !namcpy(field.name, $name) ) YYERROR; + if( !namcpy(@name, field.name, $name) ) YYERROR; auto symbol = symbol_field(PROGRAM, 0, $name); if( symbol ) { @@ -2877,7 +2879,7 @@ level_name: LEVEL ctx_name nonarray, yylineno, "", 0, cbl_field_t::linkage_t(), { 0,0,0,0, NULL, NULL, { NULL }, { NULL } }, NULL }; - if( !namcpy(field.name, $2) ) YYERROR; + if( !namcpy(@ctx_name, field.name, $2) ) YYERROR; $$ = field_add(@2, &field); if( !$$ ) { @@ -3021,7 +3023,7 @@ data_descr1: level_name struct cbl_field_t field = { 0, FldLiteralA, FldInvalid, constant_e, 0, 0, 78, nonarray, yylineno, "", 0, {}, *$data, NULL }; - if( !namcpy(field.name, $name) ) YYERROR; + if( !namcpy(@name, field.name, $name) ) YYERROR; if( field.data.initial ) { field.attr |= quoted_e; if( !cdf_value(field.name, field.data.initial) ) { @@ -3047,7 +3049,7 @@ data_descr1: level_name FldClass, FldInvalid, 0, 0, 0, 88, nonarray, yylineno, "", 0, cbl_field_t::linkage_t(), { 0,0,0,0, NULL, NULL, { NULL }, { NULL } }, NULL }; - if( !namcpy(field.name, $2) ) YYERROR; + if( !namcpy(@NAME, field.name, $2) ) YYERROR; auto fig = constant_of(constant_index(NULLS)); struct cbl_domain_t *domain = new cbl_domain_t[2]; @@ -3073,7 +3075,7 @@ data_descr1: level_name FldClass, FldInvalid, 0, 0, 0, 88, nonarray, yylineno, "", 0, cbl_field_t::linkage_t(), { 0,0,0,0, NULL, NULL, { NULL }, { NULL } }, NULL }; - if( !namcpy(field.name, $2) ) YYERROR; + if( !namcpy(@NAME, field.name, $2) ) YYERROR; struct cbl_domain_t *domain = new cbl_domain_t[ domains.size() + 1]; @@ -3188,10 +3190,7 @@ data_descr1: level_name | level_name[field] data_clauses { -#ifndef YYNOMEM -# define YYNOMEM YYERROR -#endif - assert($field == current_field()); + gcc_assert($field == current_field()); if( $data_clauses == value_clause_e ) { // only VALUE, no PIC // Error unless VALUE is a figurative constant or (quoted) string. if( $field->type != FldPointer && @@ -3887,22 +3886,14 @@ usage_clause1: usage COMPUTATIONAL[comp] native is_numeric(redefined->type) && redefined->size() == 4) { // For now, we allow POINTER to expand a 32-bit item to 64 bits. field->data.capacity = sizeof(void *); - if( yydebug ) { - yywarn("%s: expanding #%zu %s capacity %u => %u", __func__, + dbgmsg("%s: expanding #%zu %s capacity %u => %u", __func__, field_index(redefined), redefined->name, redefined->data.capacity, field->data.capacity); - } redefined->embiggen(); if( redefined->data.initial ) { - char *s = new char[1 + redefined->data.capacity]; - if( !s ) { - error_msg(@2, "could not expand initial value of %s", field->name); - YYERROR; - } - (void)! snprintf(s, 1 + redefined->data.capacity, - "%s ", redefined->data.initial); + auto s = xasprintf( "%s ", redefined->data.initial); std::replace(s, s + strlen(s), '!', char(0x20)); redefined->data.initial = s; } @@ -4339,7 +4330,7 @@ sentences: sentence { | paragraph_name[para] '.' { location_set(@para); - cbl_label_t *label = label_add(LblParagraph, $para, yylineno); + cbl_label_t *label = label_add(@para, LblParagraph, $para); if( !label ) { YYERROR; } @@ -4356,7 +4347,7 @@ sentences: sentence { | sentences paragraph_name[para] '.' { location_set(@para); - cbl_label_t *label = label_add(LblParagraph, $para, yylineno); + cbl_label_t *label = label_add(@para, LblParagraph, $para); if( !label ) { YYERROR; } @@ -6532,14 +6523,14 @@ cce_factor: NUMSTR { section_name: NAME section_kw '.' { statement_begin(@1, SECTION); - $$ = label_add(LblSection, $1, yylineno); + $$ = label_add(@1, LblSection, $1); ast_enter_section($$); apply_declaratives(); } | NAME section_kw // lexer swallows '.' before USE <label>{ statement_begin(@1, SECTION); - $$ = label_add(LblSection, $1, yylineno); + $$ = label_add(@1, LblSection, $1); ast_enter_section($$); apply_declaratives(); } [label] @@ -8069,10 +8060,6 @@ search_1_place: search_1_body search_1_body: name[table] search_varying[varying] { - // YYNOMEM first appears in Bison 3.7 -#ifndef YYNOMEM -# define YYNOMEM YYERROR -#endif statement_begin(@$, SEARCH); cbl_field_t *index = table_primary_index($table); if( !index ) { @@ -8080,10 +8067,14 @@ search_1_body: name[table] search_varying[varying] YYERROR; } - char *label_name = xasprintf("linear_search_%d", yylineno); + cbl_name_t label_name; + auto len = snprintf(label_name, sizeof(label_name), + "linear_search_%d", yylineno); + if( ! (0 < len && len < int(sizeof(label_name))) ) { + gcc_assert(false); + } cbl_label_t *name = label_add( LblSearch, label_name, yylineno ); - auto varying($varying); if( index == varying ) varying = NULL; parser_lsearch_start( name, $table, index, varying ); @@ -8135,10 +8126,6 @@ search_binary: SEARCH ALL search_2_body search_2_cases search_2_body: name[table] { - // YYNOMEM first appears in Bison 3.7 -#ifndef YYNOMEM -# define YYNOMEM YYERROR -#endif statement_begin(@$, SEARCH); char *label_name = xasprintf("binary_search_%d", yylineno); cbl_label_t *name = label_add( LblSearch, @@ -8449,7 +8436,7 @@ label_name: NAME struct cbl_label_t *label = symbol_label(PROGRAM, LblNone, 0, $1); if( !label ) { // no line number for forward declaraion - label = label_add(LblNone, $1, 0); + label = label_add(@NAME, LblNone, $1); } $$ = label; } @@ -9195,7 +9182,7 @@ label_1: qname size_t isect = 0; if( names.size() == 2 ) { - cbl_label_t *sect = label_add(LblSection, names.front(), 0); + cbl_label_t *sect = label_add(@1, LblSection, names.front()); isect = symbol_index(symbol_elem_of(sect)); } @@ -9207,7 +9194,7 @@ label_1: qname | NUMSTR { // Add a forward label with no line number, or get an existing. - $$ = label_add(LblNone, $1.string, 0); + $$ = label_add(@1, LblNone, $1.string); assert($$ != NULL); } ; @@ -11043,18 +11030,18 @@ typedef label_named<LblSection> section_named; typedef label_named<LblParagraph> paragraph_named; static struct cbl_label_t * -label_add( enum cbl_label_type_t type, const char name[], int line ) { +label_add( const YYLTYPE& loc, + enum cbl_label_type_t type, const char name[] ) { size_t parent = 0; // Verify the new paragraph doesn't conflict with a section if( type == LblParagraph ) { - assert(line == yylineno); parent = current.program_section(); auto p = std::find_if(symbols_begin(PROGRAM), symbols_end(), section_named(PROGRAM, name)); if( p != symbols_end() ) { - yywarn("paragraph %s conflicts with section %s on line %d", - name, cbl_label_of(p)->name, cbl_label_of(p)->line); + error_msg(loc, "paragraph %s conflicts with section %s on line %d", + name, cbl_label_of(p)->name, cbl_label_of(p)->line); } } @@ -11064,13 +11051,13 @@ label_add( enum cbl_label_type_t type, const char name[], int line ) { auto p = std::find_if(symbols_begin(PROGRAM), symbols_end(), paragraph_named(PROGRAM, name)); if( p != symbols_end() ) { - yywarn("section %s conflicts with paragraph %s on line %d", - name, cbl_label_of(p)->name, cbl_label_of(p)->line); + error_msg(loc, "section %s conflicts with paragraph %s on line %d", + name, cbl_label_of(p)->name, cbl_label_of(p)->line); } } - struct cbl_label_t label = { type, parent, line }; + struct cbl_label_t label = { type, parent, loc.last_line }; - if( !namcpy(label.name, name) ) return NULL; + if( !namcpy(loc, label.name, name) ) return NULL; auto p = symbol_label_add(PROGRAM, &label); if( type == LblParagraph || type == LblSection ) { @@ -11087,6 +11074,17 @@ label_add( enum cbl_label_type_t type, const char name[], int line ) { return p; } +/* + * Many label names are defined statically and so are guaranteed to be in + * bounds. Often they are created far away from the yacc metavariables, so + * there's no location to access. + */ +static struct cbl_label_t * +label_add( enum cbl_label_type_t type, const char name[], int line ) { + YYLTYPE loc { line, 1, line, 1 }; + return label_add(loc, type, name); +} + cbl_label_t * perform_t::ec_labels_t::new_label( cbl_label_type_t type, const cbl_name_t role ) @@ -11324,7 +11322,8 @@ function_descr_t function_descr_t::init( int isym ) { function_descr_t descr = { .token = FUNCTION_UDF_0, .ret_type = FldInvalid }; auto L = cbl_label_of(symbol_at(isym)); - namcpy(descr.name, L->name); + bool ok = namcpy(YYLTYPE(), descr.name, L->name); + gcc_assert(ok); return descr; } diff --git a/gcc/cobol/parse_ante.h b/gcc/cobol/parse_ante.h index 417f672277e9bf23a002feb9d06036a234db17ad..78d5af0541857449be841c52222df6accf971f7d 100644 --- a/gcc/cobol/parse_ante.h +++ b/gcc/cobol/parse_ante.h @@ -211,11 +211,12 @@ static cbl_refer_t * intrinsic_inconsistent_parameter( size_t n, cbl_refer_t *args ); static inline bool -namcpy( cbl_name_t tgt, const char *src ) { +namcpy(const YYLTYPE& loc, cbl_name_t tgt, const char *src ) { // snprintf(3): writes at most size bytes (including the terminating NUL byte) - if( -1 == snprintf(tgt, sizeof(cbl_name_t), "%s", src) ) { - dbgmsg("logic error: name truncated to '%s' (max %zu characters)", - tgt, sizeof(cbl_name_t)-1); + auto len = snprintf(tgt, sizeof(cbl_name_t), "%s", src); + if( ! (0 < len && len < int(sizeof(cbl_name_t))) ) { + error_msg(loc, "name truncated to '%s' (max %zu characters)", + tgt, sizeof(cbl_name_t)-1); return false; } return true; @@ -862,6 +863,8 @@ struct tgt_list_t { list<cbl_num_result_t> targets; }; +static struct cbl_label_t * +label_add( const YYLTYPE& loc, enum cbl_label_type_t type, const char name[] ); static struct cbl_label_t * label_add( enum cbl_label_type_t type, const char name[], int line ); @@ -1400,7 +1403,10 @@ class prog_descr_t { cbl_name_t name; const char *os_name; locale_t(const cbl_name_t name = NULL, const char *os_name = NULL) : name(""), os_name(os_name) { - if( name ) namcpy(this->name, name); + if( name ) { + bool ok = namcpy(YYLTYPE(), this->name, name); + gcc_assert(ok); + } } } locale; cbl_call_convention_t call_convention; @@ -1951,7 +1957,7 @@ static class current_t { return programs.top().locale = prog_descr_t::locale_t(name, os_name); } - bool new_program ( cbl_label_type_t type, + bool new_program ( const YYLTYPE& loc, cbl_label_type_t type, const char name[], const char os_name[], bool common, bool initial ) { @@ -1964,7 +1970,7 @@ static class current_t { .initial = initial, .os_name = os_name }; - if( !namcpy(label.name, name) ) { assert(false); return false; } + if( !namcpy(loc, label.name, name) ) { gcc_assert(false); return false; } const cbl_label_t *L; if( (L = symbol_program_add(parent, &label)) == NULL ) return false; @@ -2962,7 +2968,7 @@ static struct cbl_field_t * field_alloc( const YYLTYPE& loc, cbl_field_type_t type, size_t parent, const char name[] ) { cbl_field_t *f, field = { .type = type, .usage = FldInvalid, .parent = parent, .line = yylineno }; - if( !namcpy(field.name, name) ) return NULL; + if( !namcpy(loc, field.name, name) ) return NULL; f = field_add(loc, &field); assert(f); return f; diff --git a/gcc/cobol/symbols.cc b/gcc/cobol/symbols.cc index 02a9594f31f741251de06a229c4a97fdfd10558d..88b0480aaeddf37ba9be546db8f4d51384253fa2 100644 --- a/gcc/cobol/symbols.cc +++ b/gcc/cobol/symbols.cc @@ -3923,7 +3923,7 @@ symbol_label_add( size_t program, cbl_label_t *input ) cbl_label_t *label = symbol_label(program, input->type, input->parent, input->name); - if( label && label->line == 0 ) { + if( label && label->type == LblNone ) { const char *verb = "set"; label->type = input->type; label->parent = input->parent; diff --git a/gcc/cobol/symbols.h b/gcc/cobol/symbols.h index 1421170adfd2c7ab56aeef4afea858a24d83b110..a4ed741a4ccbcd0b6162a61efae0ab35bb64463c 100644 --- a/gcc/cobol/symbols.h +++ b/gcc/cobol/symbols.h @@ -71,6 +71,36 @@ strfromf128 (char *restrict string, size_t size, } #endif +/* Location type. Borrowed from parse.h as generated by Bison. */ +#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED +typedef struct YYLTYPE YYLTYPE; +struct YYLTYPE +{ + int first_line; + int first_column; + int last_line; + int last_column; +}; +# define YYLTYPE_IS_DECLARED 1 +# define YYLTYPE_IS_TRIVIAL 1 + +const YYLTYPE& cobol_location(); +#endif + +#if ! defined YDFLTYPE && ! defined YDFLTYPE_IS_DECLARED +typedef struct YDFLTYPE YDFLTYPE; +struct YDFLTYPE +{ + int first_line; + int first_column; + int last_line; + int last_column; +}; +# define YDFLTYPE_IS_DECLARED 1 +# define YDFLTYPE_IS_TRIVIAL 1 + +#endif + extern const char *numed_message; enum cbl_dialect_t { @@ -1174,11 +1204,13 @@ struct function_descr_t { char types[8]; std::vector<function_descr_arg_t> linkage_fields; cbl_field_type_t ret_type; - + static function_descr_t init( const char name[] ) { function_descr_t descr = {}; - snprintf( descr.name, sizeof(descr.name), "%s", name ); - return descr; // any truncation reported elsewhere + if( -1 == snprintf( descr.name, sizeof(descr.name), "%s", name ) ) { + dbgmsg("name truncated to '%s' (max %zu characters)", name); + } + return descr; // truncation also reported elsewhere ? } static function_descr_t init( int isym ); @@ -2182,24 +2214,6 @@ int rdigits_of_picture(const char *picture); int digits_of_picture(const char *picture, bool for_rdigits); bool is_picture_scaled(const char *picture); -/* Location type. Borrowed from parse.h as generated by Bison. */ -#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED -typedef struct YYLTYPE YYLTYPE; -struct YYLTYPE -{ - int first_line; - int first_column; - int last_line; - int last_column; -}; -# define YYLTYPE_IS_DECLARED 1 -# define YYLTYPE_IS_TRIVIAL 1 - -const YYLTYPE& cobol_location(); -////void gcc_location_set( const YYLTYPE& loc ); - -#endif - template <typename LOC> void gcc_location_set( const LOC& loc ); diff --git a/gcc/cobol/util.cc b/gcc/cobol/util.cc index eda924fbd68d8e82a9effa1875458f9e12eac89f..2de8dc0d3be47be090d52838245342f700065da7 100644 --- a/gcc/cobol/util.cc +++ b/gcc/cobol/util.cc @@ -2131,14 +2131,6 @@ ydferror( const char gmsgid[], ... ) { extern int yychar; extern YYLTYPE yylloc; -struct YDFLTYPE -{ - int first_line; - int first_column; - int last_line; - int last_column; -}; - /* * temp_loc_t is a hack in lieu of "%define parse.error custom". When * instantiated, if there is a lookahead token (or one is provided), it sets diff --git a/libgcobol/exceptl.h b/libgcobol/exceptl.h index ec71836b71e2ac3793a4d0c6196abddd82e57c82..de9ca6868597cc4b6acbdc15f56d0dbfb87a9a0e 100644 --- a/libgcobol/exceptl.h +++ b/libgcobol/exceptl.h @@ -223,29 +223,14 @@ struct cbl_declarative_t { * index to the matching declarative, if any. */ class ec_status_t { - char msg[132]; public: ec_type_t type, handled; - cbl_name_t statement; // e.g., "ADD" - size_t lineno; - const char *source_file; ec_status_t() : type(ec_none_e) , handled(ec_none_e) - , lineno(0) - , source_file(NULL) - { - msg[0] = statement[0] = '\0'; - } + {} - ec_status_t& update(); - ec_status_t& enable( unsigned int mask ); - - const char * exception_location() { - snprintf(msg, sizeof(msg), "%s:%zu: '%s'", source_file, lineno, statement); - return msg; - } ec_type_t unhandled() const { return ec_type_t(static_cast<unsigned int>(type) &