From ed4464c5094817e762713a3e41f1af3fa6bb37bc Mon Sep 17 00:00:00 2001
From: "James K. Lowden" <jklowden@symas.com>
Date: Tue, 16 Apr 2024 18:30:16 -0400
Subject: [PATCH] reuse of temporaries causes crashes, see sentences
 nonterminal

---
 gcc/cobol/parse.y      |   2 +-
 gcc/cobol/parse_ante.h |   2 +-
 gcc/cobol/symbols.cc   | 117 ++++++++++++++++++++---------------------
 gcc/cobol/symbols.h    |   8 ++-
 4 files changed, 61 insertions(+), 68 deletions(-)

diff --git a/gcc/cobol/parse.y b/gcc/cobol/parse.y
index 4729bf7cc276..c08baf627c84 100644
--- a/gcc/cobol/parse.y
+++ b/gcc/cobol/parse.y
@@ -4040,7 +4040,7 @@ sentences:      sentence {
 		      symbol_temporaries_free();
 		}
         |       sentences sentence {
-		  if( $1 != PARAGRAPH ) 
+		  if( false && $2 != PARAGRAPH ) 
 		      symbol_temporaries_free();
 		}
                 ;
diff --git a/gcc/cobol/parse_ante.h b/gcc/cobol/parse_ante.h
index 8d2c8a4a7a82..e48035f788fc 100644
--- a/gcc/cobol/parse_ante.h
+++ b/gcc/cobol/parse_ante.h
@@ -365,7 +365,7 @@ struct evaluate_elem_t {
   typedef list<case_t>::iterator case_iter;
   case_iter pcase;
 
-  void dump() const {
+void dump() const {
     warnx( "nother=%zu label '%s', %zu cases", nother, label.name, cases.size() );
     std::for_each( cases.begin(), cases.end(), case_t::Dump );
   }
diff --git a/gcc/cobol/symbols.cc b/gcc/cobol/symbols.cc
index 84aa35a264a4..36e8aa3a0652 100644
--- a/gcc/cobol/symbols.cc
+++ b/gcc/cobol/symbols.cc
@@ -2983,7 +2983,7 @@ static cbl_field_t *
 new_temporary_impl( enum cbl_field_type_t type )
 {
   extern int yylineno;
-  static int temp_num = 1;
+  static int nstack, nliteral; 
   static const struct cbl_field_t empty_alpha = {
                                 0, FldAlphanumeric, FldInvalid,
 				temporary_e | intermediate_e, 0, 0, 0, nonarray, 0, "",
@@ -3027,8 +3027,16 @@ new_temporary_impl( enum cbl_field_type_t type )
   }
 
   f->line = yylineno;
-  snprintf(f->name, sizeof(f->name), "_stack%d",temp_num++);
-
+  if( is_literal(type) ) {
+    snprintf(f->name, sizeof(f->name), "_literal%d",++nliteral);
+  } else {
+    snprintf(f->name, sizeof(f->name), "_stack%d",++nstack);
+    
+    if( getenv("symbol_temporaries_free") ) {
+      warnx("%s: %s, %s", __func__, f->name, 3 + cbl_field_type_str(f->type));
+    }
+  }
+  
   return f;
 }
 
@@ -3045,12 +3053,6 @@ parser_symbol_add2( cbl_field_t *field ) {
   return field;
 }
 
-static cbl_field_t *
-new_temporary_add( enum cbl_field_type_t type ) {
-  cbl_field_t *field = new_temporary_impl(type);
-  return parser_symbol_add2(field);
-}
-
 static cbl_field_t *
 new_literal_add( const char initial[], uint32_t len, enum cbl_field_attr_t attr ) {
   static char empty[2] = "\0";
@@ -3110,6 +3112,45 @@ new_literal( uint32_t len, const char initial[], enum cbl_field_attr_t attr ) {
   return temporaries.literal(initial, len, attr);
 }
 
+void
+temporaries_t::dump() const {
+  char *output;
+  extern int yylineno;
+  
+  asprintf(&output, "%4d: %zu Literals", yylineno, literals.size());
+  for( const auto& elem : used ) {
+    if( ! elem.second.empty() ) {
+      char *so_far = output;
+      asprintf(&output, "%s, %zu %s",
+               so_far, 
+               elem.second.size(), 
+               3 + cbl_field_type_str(elem.first));
+      free(so_far);
+    }
+  }
+  warnx("status: %s", output);
+  free(output);
+}
+
+temporaries_t::~temporaries_t() {
+  if( getenv( "symbol_temporaries_free" ) ) {
+    warnx("%s: %zu literals", __func__, literals.size());
+    for( const auto& elem : literals ) {
+      const literal_an& key(elem.first);
+      fprintf(stderr, "%c '%s'\n", key.is_quoted? 'Q' : ' ', key.value.c_str());
+    }
+    dump();
+  }
+}
+
+cbl_field_t *
+temporaries_t::add( cbl_field_t *field ) {
+  auto p = used[field->type].insert(field);
+  bool yn(p.second);
+  assert(yn);
+  return *p.first;
+};
+
 cbl_field_t *
 temporaries_t::reuse( cbl_field_type_t type ) {
   auto& fields = freed[type];
@@ -3123,52 +3164,23 @@ temporaries_t::reuse( cbl_field_type_t type ) {
     fields.erase(p);
   }
   
-  used[type].insert(field);
-  return field;
+  return add(field);
 }
 
 cbl_field_t *
 temporaries_t::acquire( cbl_field_type_t type ) {
   cbl_field_t *field = reuse(type);
 
-  if( field ) {
-    parser_symbol_add(field); // notify of reuse 
-  } else {
-    field = new_temporary_add(type);
-  }
-  return field;
-}
-
-size_t
-temporaries_t::keep() {
-  keepers.push(used);
-  used.clear();
-  return keepers.size();
-}
-
-void
-temporaries_t::release( size_t keeper ) {
-  if( keepers.size() != keeper ) {
-    warnx("%s: logic error: releasing %zu of %zu kept temporaries:",
-          __func__, keeper, keepers.size() );
-  }
-  assert( ! keepers.empty() );
-  assert( keepers.size() == keeper );
-  fieldmap_t& used( keepers.top() );
-
-  for( auto& elem : used ) {
-    const cbl_field_type_t& type(elem.first);
-    temporaries_t::fieldset_t& used(elem.second);
-
-    auto freer = std::inserter(freed[type],
-                               freed[type].begin());
-    std::copy( used.begin(), used.end(), freer );
+  if( !field ) {
+    field = new_temporary_impl(type);
+    add(field);
   }
-  keepers.pop();
+  return parser_symbol_add2(field); // notify of reuse 
 }
 
 void
 symbol_temporaries_free() {
+  if( getenv(__func__) ) temporaries.dump();
   for( auto& elem : temporaries.used ) {
     const cbl_field_type_t& type(elem.first);
     temporaries_t::fieldset_t& used(elem.second);
@@ -3180,23 +3192,6 @@ symbol_temporaries_free() {
   }
 }
 
-size_t
-symbol_temporaries_push() {
-  return temporaries.keep();
-}
-
-void
-symbol_temporaries_pop( size_t kept ) {
-  return temporaries.release( kept );
-}
-
-void
-temporaries_t::add( cbl_field_t *field ) {
-  auto p = used[field->type].insert(field);
-  bool yn(p.second);
-  assert(yn);
-};
-
 cbl_field_t *
 new_alphanumeric( size_t capacity ) {
   cbl_field_t * field = new_temporary_impl(FldAlphanumeric);
diff --git a/gcc/cobol/symbols.h b/gcc/cobol/symbols.h
index 1181b0b3baae..14cbbb2431dc 100644
--- a/gcc/cobol/symbols.h
+++ b/gcc/cobol/symbols.h
@@ -1246,13 +1246,11 @@ public:
   cbl_field_t * literal( const char value[], uint32_t len, cbl_field_attr_t attr  = none_e );
   cbl_field_t * reuse( cbl_field_type_t type );
   cbl_field_t * acquire( cbl_field_type_t type );
-  size_t keep();
-  void release( size_t kept);
-  void add( cbl_field_t *field );
+  cbl_field_t *  add( cbl_field_t *field );
+  void dump() const;
+  ~temporaries_t();
 };
 
-size_t symbol_temporaries_push();
-void symbol_temporaries_pop( size_t kept );
 
 static inline bool is_table( const cbl_field_t *field ) {
   return field && field->occurs.ntimes() > 0;
-- 
GitLab