From b6ae080cd687d93128d4c896979fcfcee5658951 Mon Sep 17 00:00:00 2001 From: Stephane Chauveau Date: Wed, 7 Mar 2018 14:21:01 +0100 Subject: [PATCH] [flang] Fix misc issues with closing of LabelDo Original-commit: flang-compiler/f18@8134331da8a21b40f6c61bc371f3af66bf3662c0 Reviewed-on: https://github.com/flang-compiler/f18/pull/24 Tree-same-pre-rewrite: false --- flang/tools/f18/sema-impl.cc | 136 +++++++++++++++++++++++++++++------ flang/tools/f18/test-sema.cc | 7 ++ 2 files changed, 121 insertions(+), 22 deletions(-) diff --git a/flang/tools/f18/sema-impl.cc b/flang/tools/f18/sema-impl.cc index 96593ba4978a..1a22747bd8fc 100644 --- a/flang/tools/f18/sema-impl.cc +++ b/flang/tools/f18/sema-impl.cc @@ -801,7 +801,12 @@ public: SMap * current_smap_ ; std::map construct_name_ ; - + + // Set of all labe-DO statement that are still open. + // The key is the LabelDoStmt index + // The value is the required label. + std::map opened_label_do_; + public: Scope *EnterScope(Scope *s) { @@ -1000,8 +1005,44 @@ public: assert(current_smap_) ; return *current_smap_ ; } - + void OpenLabelDo(SMap::Index dostmt, int label) + { + opened_label_do_[dostmt] = label ; + } + + void CloseLabelDo(SMap::Index dostmt) + { + opened_label_do_.erase(dostmt) ; + } + + // If stmt is an opened LabelDo, then return its label. + // In all other cases, return 0. + // + // This function can be safely called even if stmt is + // not a LabelStmt + // + int GetLabelOfOpenedLabelDo(SMap::Index stmt) + { + auto it = opened_label_do_.find(stmt); + if ( it != opened_label_do_.end() ) + return it->second ; + else + return 0 ; + } + + // return true if the specified label matches any currently opened LabelDo + bool MatchAnyOpenedLabelDo(int label) + { + auto smap = GetStatementMap() ; + for (auto it : opened_label_do_ ) { + if ( it.second == label ) + return true; + } + return false; + } + + bool ValidEndOfLabelDo(StmtClass sclass) { @@ -1092,10 +1133,12 @@ public: auto sgroup = StmtClassToGroup(sclass); + + if ( smap.Size() >= 1 ) { // We need to add the statement to the map but before, we have to - // handle the specific case of the LabelDo. + // handle the specific case of the LabelDo. SMap::Index last = smap.Size(); SMap::Index label_do = SMap::None; if ( smap.GetGroup(last) == StmtGroup::Single ) { @@ -1105,14 +1148,16 @@ public: } if ( label_do != SMap::None ) { if ( smap.GetClass(label_do) == StmtClass::LabelDo ) { - if ( smap.GetLabelDoLabel(label_do) == sema.stmt_label ) { + if ( GetLabelOfOpenedLabelDo(label_do) == sema.stmt_label ) { if ( ! ValidEndOfLabelDo(sclass) ) { FAIL("Statement cannot end a DO label"); + } else if ( sclass == StmtClass::EndDo ) { + CloseLabelDo(label_do); } } else if ( sclass == StmtClass::EndDo ) { - FAIL("ENDDO label does not match previous DO label"); + FAIL("ENDDO label does not match previous DO-label"); } else if ( sgroup==StmtGroup::Part || sgroup==StmtGroup::End ) { - FAIL("Unterminated DO label statement"); + FAIL("Unterminated DO-label statement"); } } } @@ -1127,36 +1172,71 @@ public: if (sgroup == StmtGroup::Single || sgroup == StmtGroup::End ) { SMap::Index s; - if (sgroup == StmtGroup::End) + if (sclass == StmtClass::EndDo ) + s = sema.stmt_index ; + else if (sgroup == StmtGroup::End) s = smap.StartOfConstruct(sema.stmt_index); else // StmtGroup::Single s = sema.stmt_index ; int label = smap.GetLabel(s) ; if ( label > 0 ) { - SMap::Index parent = smap.GetParent(s) ; - // Insert a DummyEndDo for each enclosing LabelDo that - // matches the label of the added statement or construct - while ( parent!= SMap::None && - ( smap.GetClass(parent) == StmtClass::LabelDo || - smap.GetClass(parent) == StmtClass::LabelDoWhile || - smap.GetClass(parent) == StmtClass::LabelDoConcurrent - ) && - smap.GetLabelDoLabel(parent) + // For an enddo, go up one more level because we just + // closed that loop (but there could be more loops to close) + if (sclass == StmtClass::EndDo ) + s = smap.StartOfConstruct(s) ; + + SMap::Index parent = smap.GetParent(s) ; + + // Insert a DummyEndDo for each opened LabelDo that + // matches the label of the added statement or construct. + while ( parent != SMap::None && + //( smap.GetClass(parent) == StmtClass::LabelDo || + // smap.GetClass(parent) == StmtClass::LabelDoWhile || + // smap.GetClass(parent) == StmtClass::LabelDoConcurrent + // ) && + // isAnOpenLabelDo(parent) && + // smap.GetLabelDoLabel(parent) == label && + GetLabelOfOpenedLabelDo(parent) == label ) { auto name = GetConstructName(parent); if (name) { + // + // Our DummyEndDo cannot be used to close a named LabelDo. + // For instance, the following is not legal: + // foobar: DO 666 i=1,n + // ... + // 666 CONTINUE FAIL("Statement #" << sema.stmt_index << " is ending the named DO label #" << parent) ; } - smap.Add( StmtClass::DummyEndDo, 0 ) ; + smap.Add( StmtClass::DummyEndDo, 0 ) ; + CloseLabelDo(parent) ; parent = smap.GetParent(parent) ; } } } - + + // TODO: add a data structure to track all opened 'LabelDo' + // and after inserting the + + // If the label of the added statement was supposed to + // close some opened LabelDo then they should be now be + // closed. + // + // Any opened LabelDo matching the added label indicates + // a nesting problem + // + int added_label = smap.GetLabel(sema.stmt_index) ; + if ( added_label ) { + if ( MatchAnyOpenedLabelDo(added_label) ) { + FAIL("Statement with label " << added_label << " is not properly" + " nested to close all corresponding label DO statement"); + } + } + return sema; } @@ -2344,7 +2424,16 @@ public: // Inform the Statement Map of the required end label. int end_label = int(std::get<1>(x.t)) ; // TODO: check label is in 1:99999 range - smap.SetLabelDoLabel(sema.stmt_index, end_label) ; + //smap.SetLabelDoLabel(sema.stmt_index, end_label) ; + OpenLabelDo( sema.stmt_index, end_label); + + Provenance previous_loc; + if ( GetLabelTable().find(end_label, previous_loc) ) { + // Early fail when the label already exists. + // This is actually optional since a "Duplicate Label" or "a END mismatch" error + // should occur later. + FAIL("Label " << end_label << " required by DO statement is already declared") ; + } // And also record the construct name auto name = sm::Identifier::get( std::get<0>(x.t) ); @@ -2851,13 +2940,15 @@ public: // the name of the construct we are looking for (can be null) const sm::Identifier * target_name = sm::Identifier::get(x.v) ; + // Reminder: Unlike in EXIT, the target of a CYCLE statement is always + // a DO so the target resolution are similar but not identical. SMap::Index target_do = SMap::None ; SMap::Index construct = sema.stmt_index ; - // At that point, construct refers to the CYCLE statment which is not a - // construct index (i.e. a Start statement). However, in the loop below, - // it will be assigned a proper construct index. + // Note: At that point, 'construct' refers to the CYCLE statment which + // is not a construct index (i.e. a Start statement). However, in the + // loop below, 'construct' will be assigned a proper construct index. bool done=false ; while (!done) @@ -2919,6 +3010,7 @@ public: case StmtClass::Block: case StmtClass::Associate: case StmtClass::WhereConstruct: + // A CYCLE statement can be used to exit those constructs but they are proper targets break; case StmtClass::Program: diff --git a/flang/tools/f18/test-sema.cc b/flang/tools/f18/test-sema.cc index edc0d505df8a..d089b6883ce8 100644 --- a/flang/tools/f18/test-sema.cc +++ b/flang/tools/f18/test-sema.cc @@ -54,6 +54,13 @@ int main(int argc, char *const argv[]) { cooked.Marshal(); ParseState state{cooked}; UserState ustate; + + state + //.set_inFixedForm(true) + //.set_strictConformance(false) + .set_userState(&ustate) + ; + std::optional result{program.Parse(&state)}; if (!result.has_value() || state.anyErrorRecovery()) { std::cerr << "parse FAILED\n";