diff options
-rw-r--r-- | include/flang/Basic/DiagnosticSemaKinds.td | 6 | ||||
-rw-r--r-- | include/flang/Sema/Scope.h | 12 | ||||
-rw-r--r-- | include/flang/Sema/Sema.h | 19 | ||||
-rw-r--r-- | lib/Sema/Sema.cpp | 42 | ||||
-rw-r--r-- | lib/Sema/SemaExecStmt.cpp | 354 | ||||
-rw-r--r-- | test/Parser/do.f95 | 3 | ||||
-rw-r--r-- | test/Parser/if.f95 | 4 | ||||
-rw-r--r-- | test/Sema/beginEndRecovery.f95 | 36 | ||||
-rw-r--r-- | test/Sema/do.f95 | 13 | ||||
-rw-r--r-- | test/Sema/dowhile.f95 | 6 | ||||
-rw-r--r-- | test/Sema/if.f95 | 12 | ||||
-rw-r--r-- | test/Sema/subprogram.f95 | 5 |
12 files changed, 283 insertions, 229 deletions
diff --git a/include/flang/Basic/DiagnosticSemaKinds.td b/include/flang/Basic/DiagnosticSemaKinds.td index f96aece914..dc3f105672 100644 --- a/include/flang/Basic/DiagnosticSemaKinds.td +++ b/include/flang/Basic/DiagnosticSemaKinds.td @@ -112,15 +112,15 @@ def warn_unused_stmt_label : Warning<"unused statement label '%0'">, InGroup<UnusedLabel>, DefaultIgnore; def err_expected_stmt_label_end_do : Error< - "expected a statement with a statement label '%0' to mark the end of a do loop">; + "expected a do termination statement with a statement label '%0'">; def err_invalid_do_terminating_stmt : Error< "invalid terminating statement for a DO loop">; def err_stmt_not_in_if : Error< - "'%0' statement must be a part of an if construct">; + "use of '%0' outside an if construct">; def err_end_do_without_do : Error< - "use of 'END DO' without the do statement">; + "use of 'end do' outside a do construct">; def err_use_implicit_none_stmt : Error< "use of 'IMPLICIT NONE' after 'IMPLICIT'">; diff --git a/include/flang/Sema/Scope.h b/include/flang/Sema/Scope.h index 8036cc4e8a..d04f0bfb71 100644 --- a/include/flang/Sema/Scope.h +++ b/include/flang/Sema/Scope.h @@ -56,8 +56,9 @@ public: Entry(IfStmt *S) : Statement(S), BeginOffset(0) { } - inline bool is(Stmt::StmtClass StmtType) const { - return Statement->getStmtClass() == StmtType; + + bool hasExpectedDoLabel() const { + return ExpectedEndDoLabel != nullptr; } }; @@ -75,13 +76,12 @@ public: return StmtList; } - inline const Entry &LastEntered() const { + const Entry &LastEntered() const { return ControlFlowStack.back(); } - inline bool HasEntered() const { + bool HasEntered() const { return ControlFlowStack.size() != 0; } - bool HasEntered(Stmt::StmtClass StmtType) const; void Append(Stmt *S); private: @@ -191,7 +191,7 @@ public: bool ApplyNone(); /// \brief returns true if IMPLICIT NONE was used in this scope. - inline bool isNoneInThisScope() const { + bool isNoneInThisScope() const { return None; } diff --git a/include/flang/Sema/Sema.h b/include/flang/Sema/Sema.h index f09e8d0cd6..dfe25865ed 100644 --- a/include/flang/Sema/Sema.h +++ b/include/flang/Sema/Sema.h @@ -600,6 +600,25 @@ public: SourceLocation Loc, bool ReportUnterminatedLabeledDo = true); + /// Leaves the last block construct, and performs any clean up + /// that might be needed. + void LeaveLastBlock(); + + /// Leaves block constructs until a do construct is reached. + /// NB: the do statements with a termination label such as DO 100 I = .. + /// are popped. + Stmt *LeaveBlocksUntilDo(SourceLocation Loc); + + /// Returns true if the current statement is inside a do construct which + /// is terminated by the given statement label. + bool IsInLabeledDo(const Expr *StmtLabel); + + /// Leaves block constructs until a label termination do construct is reached. + DoStmt *LeaveBlocksUntilLabeledDo(SourceLocation Loc, const Expr *StmtLabel); + + /// Leaves block constructs until an if construct is reached. + IfStmt *LeaveBlocksUntilIf(SourceLocation Loc); + }; } // end flang namespace diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 1bf7b7bd86..7275cd9793 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -76,39 +76,6 @@ void Sema::PushExecutableProgramUnit(ExecutableProgramUnitScope &Scope) { CurExecutableStmts = &Scope.Body; } -// Unterminated labeled do statement -static void ReportUnterminatedLabeledDoStmt(DiagnosticsEngine &Diags, - const BlockStmtBuilder::Entry &S, - SourceLocation Loc) { - std::string Str; - llvm::raw_string_ostream Stream(Str); - S.ExpectedEndDoLabel->dump(Stream); - Diags.Report(Loc, diag::err_expected_stmt_label_end_do) << Stream.str(); -} - -// Unterminated if/do statement -void Sema::ReportUnterminatedStmt(const BlockStmtBuilder::Entry &S, - SourceLocation Loc, - bool ReportUnterminatedLabeledDo) { - const char * Keyword; - switch(S.Statement->getStmtClass()) { - case Stmt::IfStmtClass: Keyword = "END IF"; break; - case Stmt::DoWhileStmtClass: - case Stmt::DoStmtClass: { - if(S.ExpectedEndDoLabel) { - if(ReportUnterminatedLabeledDo) - ReportUnterminatedLabeledDoStmt(Diags, S, Loc); - return; - } - else Keyword = "END DO"; - break; - } - default: - llvm_unreachable("Invalid stmt"); - } - Diags.Report(Loc, diag::err_expected_kw) << Keyword; -} - void Sema::PopExecutableProgramUnit(SourceLocation Loc) { // Fix the forward statement label references @@ -162,7 +129,7 @@ void BlockStmtBuilder::Enter(Entry S) { } Stmt *BlockStmtBuilder::CreateBody(ASTContext &C, - const Entry &Last) { + const Entry &Last) { auto Ref = ArrayRef<Stmt*>(StmtList); return BlockStmt::Create(C, Last.Statement->getLocation(), ArrayRef<Stmt*>(Ref.begin() + Last.BeginOffset, @@ -198,13 +165,6 @@ Stmt *BlockStmtBuilder::LeaveOuterBody(ASTContext &C, SourceLocation Loc) { return BlockStmt::Create(C, Loc, StmtList); } -bool BlockStmtBuilder::HasEntered(Stmt::StmtClass StmtType) const { - for(auto I : ControlFlowStack) { - if(I.is(StmtType)) return true; - } - return false; -} - void BlockStmtBuilder::Append(Stmt *S) { assert(S); StmtList.push_back(S); diff --git a/lib/Sema/SemaExecStmt.cpp b/lib/Sema/SemaExecStmt.cpp index d138d448d0..708dc00097 100644 --- a/lib/Sema/SemaExecStmt.cpp +++ b/lib/Sema/SemaExecStmt.cpp @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// // -// This file implements the checking and AST construction for the DATA -// statement. +// This file implements the checking and AST construction for the executable +// statements. // //===----------------------------------------------------------------------===// @@ -16,6 +16,7 @@ #include "flang/Sema/DeclSpec.h" #include "flang/Sema/SemaDiagnostic.h" #include "flang/Sema/SemaInternal.h" +#include "flang/Parse/ParseDiagnostic.h" #include "flang/AST/ASTContext.h" #include "flang/AST/Decl.h" #include "flang/AST/Stmt.h" @@ -103,6 +104,10 @@ StmtResult Sema::ActOnGotoStmt(ASTContext &C, SourceLocation Loc, return Result; } +// ========================================================================= +// Block statements entry +// ========================================================================= + StmtResult Sema::ActOnIfStmt(ASTContext &C, SourceLocation Loc, ExprResult Condition, Expr *StmtLabel) { if(Condition.isUsable()) @@ -116,98 +121,6 @@ StmtResult Sema::ActOnIfStmt(ASTContext &C, SourceLocation Loc, return Result; } -StmtResult Sema::ActOnElseIfStmt(ASTContext &C, SourceLocation Loc, - ExprResult Condition, Expr *StmtLabel) { - if(!getCurrentBody()->HasEntered() || - !getCurrentBody()->LastEntered().is(Stmt::IfStmtClass)) { - if(getCurrentBody()->HasEntered(Stmt::IfStmtClass)) - ReportUnterminatedStmt( getCurrentBody()->LastEntered(), Loc); - else - Diags.Report(Loc, diag::err_stmt_not_in_if) << "ELSE IF"; - return StmtError(); - } - - // typecheck - if(Condition.isUsable()) - StmtRequiresLogicalExpression(Loc, Condition.get()); - - auto Result = IfStmt::Create(C, Loc, Condition.get(), StmtLabel); - auto ParentIf = cast<IfStmt>(getCurrentBody()->LastEntered().Statement); - getCurrentBody()->Leave(C); - if(Condition.isUsable()) - ParentIf->setElseStmt(Result); - if(StmtLabel) DeclareStatementLabel(StmtLabel, Result); - getCurrentBody()->Enter(Result); - return Result; -} - -StmtResult Sema::ActOnElseStmt(ASTContext &C, SourceLocation Loc, Expr *StmtLabel) { - if(!getCurrentBody()->HasEntered() || - !getCurrentBody()->LastEntered().is(Stmt::IfStmtClass)) { - if(getCurrentBody()->HasEntered(Stmt::IfStmtClass)) - ReportUnterminatedStmt(getCurrentBody()->LastEntered(), Loc); - else - Diags.Report(Loc, diag::err_stmt_not_in_if) << "ELSE"; - return StmtError(); - } - auto Result = ConstructPartStmt::Create(C, ConstructPartStmt::ElseStmtClass, Loc, nullptr, StmtLabel); - getCurrentBody()->Append(Result); - getCurrentBody()->LeaveIfThen(C); - if(StmtLabel) DeclareStatementLabel(StmtLabel, Result); - return Result; -} - -StmtResult Sema::ActOnEndIfStmt(ASTContext &C, SourceLocation Loc, Expr *StmtLabel) { - // Report begin .. end mismatch - if(!getCurrentBody()->HasEntered() || - !getCurrentBody()->LastEntered().is(Stmt::IfStmtClass)) { - if(getCurrentBody()->HasEntered(Stmt::IfStmtClass)) - ReportUnterminatedStmt(getCurrentBody()->LastEntered(), Loc); - else - Diags.Report(Loc, diag::err_stmt_not_in_if) << "END IF"; - return StmtError(); - } - - auto Result = ConstructPartStmt::Create(C, ConstructPartStmt::EndIfStmtClass, Loc, nullptr, StmtLabel); - getCurrentBody()->Append(Result); - getCurrentBody()->Leave(C); - if(StmtLabel) DeclareStatementLabel(StmtLabel, Result); - return Result; -} - -/// The terminal statement of a DO-loop must not be an unconditional GO TO, -/// assigned GO TO, arithmetic IF, block IF, ELSE IF, ELSE, END IF, RETURN, STOP, END, or DO statement. -/// If the terminal statement of a DO-loop is a logical IF statement, -/// it may contain any executable statement except a DO, -/// block IF, ELSE IF, ELSE, END IF, END, or another logical IF statement. -/// -/// FIXME: TODO full -static bool IsValidDoLogicalIfThenStatement(const Stmt *S) { - switch(S->getStmtClass()) { - case Stmt::DoStmtClass: case Stmt::IfStmtClass: case Stmt::DoWhileStmtClass: - case Stmt::ConstructPartStmtClass: - return false; - default: - return true; - } -} - -bool Sema::IsValidDoTerminatingStatement(const Stmt *S) { - switch(S->getStmtClass()) { - case Stmt::GotoStmtClass: case Stmt::AssignedGotoStmtClass: - case Stmt::StopStmtClass: case Stmt::DoStmtClass: - case Stmt::DoWhileStmtClass: - case Stmt::ConstructPartStmtClass: - return false; - case Stmt::IfStmtClass: { - auto NextStmt = cast<IfStmt>(S)->getThenStmt(); - return NextStmt && IsValidDoLogicalIfThenStatement(NextStmt); - } - default: - return true; - } -} - void StmtLabelResolver::VisitDoStmt(DoStmt *S) { S->setTerminatingStmt(StmtLabelReference(StmtLabelDecl)); } @@ -271,44 +184,6 @@ StmtResult Sema::ActOnDoStmt(ASTContext &C, SourceLocation Loc, SourceLocation E return Result; } -/// FIXME: Fortran 90+: make multiple do end at one label obsolete -void Sema::CheckStatementLabelEndDo(Expr *StmtLabel, Stmt *S) { - if(!getCurrentBody()->HasEntered()) - return; - - auto I = getCurrentBody()->ControlFlowStack.size(); - size_t LastUnterminated = 0; - do { - I--; - if(!isa<DoStmt>(getCurrentBody()->ControlFlowStack[I].Statement)) { - if(!LastUnterminated) LastUnterminated = I; - } else { - auto ParentDo = cast<DoStmt>(getCurrentBody()->ControlFlowStack[I].Statement); - auto ParentDoExpectedLabel = getCurrentBody()->ControlFlowStack[I].ExpectedEndDoLabel; - if(!ParentDoExpectedLabel) { - if(!LastUnterminated) LastUnterminated = I; - } else { - if(getCurrentStmtLabelScope()->IsSame(ParentDoExpectedLabel, StmtLabel)) { - // END DO - getCurrentStmtLabelScope()->RemoveForwardReference(ParentDo); - if(!IsValidDoTerminatingStatement(S)) { - Diags.Report(S->getLocation(), - diag::err_invalid_do_terminating_stmt); - } - ParentDo->setTerminatingStmt(StmtLabelReference(S)); - if(!LastUnterminated) { - RemoveLoopVar(ParentDo->getDoVar()); - getCurrentBody()->Leave(Context); - } - else - ReportUnterminatedStmt(getCurrentBody()->ControlFlowStack[LastUnterminated], - S->getLocation()); - } else if(!LastUnterminated) LastUnterminated = I; - } - } - } while(I>0); -} - StmtResult Sema::ActOnDoWhileStmt(ASTContext &C, SourceLocation Loc, ExprResult Condition, Expr *StmtLabel) { if(Condition.isUsable()) @@ -321,43 +196,212 @@ StmtResult Sema::ActOnDoWhileStmt(ASTContext &C, SourceLocation Loc, ExprResult return Result; } -StmtResult Sema::ActOnEndDoStmt(ASTContext &C, SourceLocation Loc, Expr *StmtLabel) { - // Report begin .. end mismatch - if(!getCurrentBody()->HasEntered() || - (!isa<DoStmt>(getCurrentBody()->LastEntered().Statement) && - !isa<DoWhileStmt>(getCurrentBody()->LastEntered().Statement))) { - bool HasMatchingDo = false; - for(auto I : getCurrentBody()->ControlFlowStack) { - if(isa<DoWhileStmt>(I.Statement) || - (isa<DoStmt>(I.Statement) && !I.ExpectedEndDoLabel)) { - HasMatchingDo = true; - break; + +// ============================================================= +// Block statements termination and control flow +// ============================================================= + +void Sema::ReportUnterminatedStmt(const BlockStmtBuilder::Entry &S, + SourceLocation Loc, + bool ReportUnterminatedLabeledDo) { + const char *Keyword; + const char *BeginKeyword; + switch(S.Statement->getStmtClass()) { + case Stmt::IfStmtClass: + Keyword = "end if"; + BeginKeyword = "if"; + break; + case Stmt::DoWhileStmtClass: + case Stmt::DoStmtClass: { + if(S.ExpectedEndDoLabel) { + if(ReportUnterminatedLabeledDo) { + std::string Str; + llvm::raw_string_ostream Stream(Str); + S.ExpectedEndDoLabel->dump(Stream); + Diags.Report(Loc, diag::err_expected_stmt_label_end_do) << Stream.str(); + Diags.Report(S.Statement->getLocation(), diag::note_matching) << "do"; } + return; } - if(!HasMatchingDo) - Diags.Report(Loc, diag::err_end_do_without_do); - else ReportUnterminatedStmt(getCurrentBody()->LastEntered(), Loc); - return StmtError(); + Keyword = "end do"; + BeginKeyword = "do"; + break; + } + default: + llvm_unreachable("Invalid stmt"); + } + Diags.Report(Loc, diag::err_expected_kw) << Keyword; + Diags.Report(S.Statement->getLocation(), diag::note_matching) << BeginKeyword; +} + +void Sema::LeaveLastBlock() { + auto Last = getCurrentBody()->LastEntered().Statement; + if(auto Do = dyn_cast<DoStmt>(Last)) { + RemoveLoopVar(Do->getDoVar()); } + getCurrentBody()->Leave(Context); +} - auto Last = getCurrentBody()->LastEntered(); +IfStmt *Sema::LeaveBlocksUntilIf(SourceLocation Loc) { + auto Stack = getCurrentBody()->ControlFlowStack; + for(size_t I = Stack.size(); I != 0;) { + --I; + if(auto If = dyn_cast<IfStmt>(Stack[I].Statement)) + return If; + ReportUnterminatedStmt(Stack[I], Loc); + LeaveLastBlock(); + } + return nullptr; +} - if(auto Do = dyn_cast<DoStmt>(Last.Statement)) { - // If last loop was a DO with terminating label, we expect it to finish before this loop - if(getCurrentBody()->LastEntered().ExpectedEndDoLabel) { - //FIXME: ReportUnterminatedLabeledDoStmt(getCurrentBody()->LastEntered(), Loc); - return StmtError(); +Stmt *Sema::LeaveBlocksUntilDo(SourceLocation Loc) { + auto Stack = getCurrentBody()->ControlFlowStack; + for(size_t I = Stack.size(); I != 0;) { + --I; + auto S = Stack[I].Statement; + if(isa<DoWhileStmt>(S) || + isa<DoStmt>(S) && !Stack[I].hasExpectedDoLabel()) + return S; + ReportUnterminatedStmt(Stack[I], Loc); + LeaveLastBlock(); + } + return nullptr; +} + +/// The terminal statement of a DO-loop must not be an unconditional GO TO, +/// assigned GO TO, arithmetic IF, block IF, ELSE IF, ELSE, END IF, RETURN, STOP, END, or DO statement. +/// If the terminal statement of a DO-loop is a logical IF statement, +/// it may contain any executable statement except a DO, +/// block IF, ELSE IF, ELSE, END IF, END, or another logical IF statement. +/// +/// FIXME: TODO full +static bool IsValidDoLogicalIfThenStatement(const Stmt *S) { + switch(S->getStmtClass()) { + case Stmt::DoStmtClass: case Stmt::IfStmtClass: case Stmt::DoWhileStmtClass: + case Stmt::ConstructPartStmtClass: + return false; + default: + return true; + } +} + +bool Sema::IsValidDoTerminatingStatement(const Stmt *S) { + switch(S->getStmtClass()) { + case Stmt::GotoStmtClass: case Stmt::AssignedGotoStmtClass: + case Stmt::StopStmtClass: case Stmt::DoStmtClass: + case Stmt::DoWhileStmtClass: + case Stmt::ConstructPartStmtClass: + return false; + case Stmt::IfStmtClass: { + auto NextStmt = cast<IfStmt>(S)->getThenStmt(); + return NextStmt && IsValidDoLogicalIfThenStatement(NextStmt); + } + default: + return true; + } +} + +bool Sema::IsInLabeledDo(const Expr *StmtLabel) { + auto Stack = getCurrentBody()->ControlFlowStack; + for(size_t I = Stack.size(); I != 0;) { + --I; + if(isa<DoStmt>(Stack[I].Statement)) { + if(Stack[I].hasExpectedDoLabel()) { + if(getCurrentStmtLabelScope()->IsSame(Stack[I].ExpectedEndDoLabel, StmtLabel)) + return true; + } } - RemoveLoopVar(Do->getDoVar()); } + return false; +} + +DoStmt *Sema::LeaveBlocksUntilLabeledDo(SourceLocation Loc, const Expr *StmtLabel) { + auto Stack = getCurrentBody()->ControlFlowStack; + for(size_t I = Stack.size(); I != 0;) { + --I; + if(auto Do = dyn_cast<DoStmt>(Stack[I].Statement)) { + if(Stack[I].hasExpectedDoLabel()) { + if(getCurrentStmtLabelScope()->IsSame(Stack[I].ExpectedEndDoLabel, StmtLabel)) + return Do; + } + } + ReportUnterminatedStmt(Stack[I], Loc); + LeaveLastBlock(); + } + return nullptr; +} + +StmtResult Sema::ActOnElseIfStmt(ASTContext &C, SourceLocation Loc, + ExprResult Condition, Expr *StmtLabel) { + auto IfBegin = LeaveBlocksUntilIf(Loc); + if(!IfBegin) + Diags.Report(Loc, diag::err_stmt_not_in_if) << "else if"; + + // typecheck + if(Condition.isUsable()) + StmtRequiresLogicalExpression(Loc, Condition.get()); + + auto Result = IfStmt::Create(C, Loc, Condition.get(), StmtLabel); + if(IfBegin) { + LeaveLastBlock(); + if(Condition.isUsable()) + IfBegin->setElseStmt(Result); + } + if(StmtLabel) DeclareStatementLabel(StmtLabel, Result); + getCurrentBody()->Enter(Result); + return Result; +} + +StmtResult Sema::ActOnElseStmt(ASTContext &C, SourceLocation Loc, Expr *StmtLabel) { + auto IfBegin = LeaveBlocksUntilIf(Loc); + if(!IfBegin) + Diags.Report(Loc, diag::err_stmt_not_in_if) << "else"; + + auto Result = ConstructPartStmt::Create(C, ConstructPartStmt::ElseStmtClass, Loc, nullptr, StmtLabel); + getCurrentBody()->Append(Result); + if(IfBegin) getCurrentBody()->LeaveIfThen(C); + if(StmtLabel) DeclareStatementLabel(StmtLabel, Result); + return Result; +} + +StmtResult Sema::ActOnEndIfStmt(ASTContext &C, SourceLocation Loc, Expr *StmtLabel) { + auto IfBegin = LeaveBlocksUntilIf(Loc); + if(!IfBegin) + Diags.Report(Loc, diag::err_stmt_not_in_if) << "end if"; + + auto Result = ConstructPartStmt::Create(C, ConstructPartStmt::EndIfStmtClass, Loc, nullptr, StmtLabel); + getCurrentBody()->Append(Result); + if(IfBegin) LeaveLastBlock(); + if(StmtLabel) DeclareStatementLabel(StmtLabel, Result); + return Result; +} + +StmtResult Sema::ActOnEndDoStmt(ASTContext &C, SourceLocation Loc, Expr *StmtLabel) { + auto DoBegin = LeaveBlocksUntilDo(Loc); + if(!DoBegin) + Diags.Report(Loc, diag::err_end_do_without_do); auto Result = ConstructPartStmt::Create(C, ConstructPartStmt::EndDoStmtClass, Loc, nullptr, StmtLabel); getCurrentBody()->Append(Result); - getCurrentBody()->Leave(C); + if(DoBegin) LeaveLastBlock(); if(StmtLabel) DeclareStatementLabel(StmtLabel, Result); return Result; } +/// FIXME: Fortran 90+: make multiple do end at one label obsolete +void Sema::CheckStatementLabelEndDo(Expr *StmtLabel, Stmt *S) { + if(!getCurrentBody()->HasEntered()) return; + if(!IsInLabeledDo(StmtLabel)) return; + auto DoBegin = LeaveBlocksUntilLabeledDo(S->getLocation(), StmtLabel); + + getCurrentStmtLabelScope()->RemoveForwardReference(DoBegin); + if(!IsValidDoTerminatingStatement(S)) + Diags.Report(S->getLocation(), diag::err_invalid_do_terminating_stmt); + DoBegin->setTerminatingStmt(StmtLabelReference(S)); + LeaveLastBlock(); +} + + StmtResult Sema::ActOnContinueStmt(ASTContext &C, SourceLocation Loc, Expr *StmtLabel) { auto Result = ContinueStmt::Create(C, Loc, StmtLabel); getCurrentBody()->Append(Result); diff --git a/test/Parser/do.f95 b/test/Parser/do.f95 index 2f3d69a94a..d732f491a7 100644 --- a/test/Parser/do.f95 +++ b/test/Parser/do.f95 @@ -50,7 +50,6 @@ PROGRAM dotest ENDDO DO x I = 1,2 ! expected-error {{expected '='}} - ! END DO + END DO - DO I = 1,5 ! expected-error@+1 {{expected 'END DO'}} END PROGRAM diff --git a/test/Parser/if.f95 b/test/Parser/if.f95 index 2c3397bc13..7657c53155 100644 --- a/test/Parser/if.f95 +++ b/test/Parser/if.f95 @@ -56,6 +56,6 @@ PROGRAM iftest ENDIF END IF - IF(1 == 2) THEN - C = "NO" ! expected-error@+1 {{expected 'END IF'}} + IF(1 == 2) THEN ! expected-note {{to match this 'if'}} + C = "NO" ! expected-error@+1 {{expected 'end if'}} END PROGRAM iftest diff --git a/test/Sema/beginEndRecovery.f95 b/test/Sema/beginEndRecovery.f95 new file mode 100644 index 0000000000..4defe9b5db --- /dev/null +++ b/test/Sema/beginEndRecovery.f95 @@ -0,0 +1,36 @@ +! RUN: %flang -fsyntax-only -verify < %s + +program recovery + + do i = 1, 10 + if (i == 0) then ! expected-note {{to match this 'if'}} + end do ! expected-error {{expected 'end if'}} + + do while(.true.) ! expected-error@+3 {{expected a do termination statement with a statement label '100'}} + do 100 i = 1, 10 ! expected-note {{to match this 'do'}} + if (i == 0) then ! expected-note {{to match this 'if'}} + end do ! expected-error {{expected 'end if'}} + + i = 0 + + if(i == 1) then + do i = 1, 10 ! expected-note {{to match this 'do'}} + end if ! expected-error {{expected 'end do'}} + + if(i == 1) then + do i = 1, 10 ! expected-note {{to match this 'do'}} + else ! expected-error {{expected 'end do'}} + end if + + if(i == 1) then + do 100 i = 1,10 ! expected-note {{to match this 'do'}} + else if(i == 3) then ! expected-error {{expected a do termination statement with a statement label '100'}} + end if + + do 200 i = 1,10 + do j = 1,10 ! expected-note {{to match this 'do'}} +300 print *,i +200 continue ! expected-error {{expected 'end do'}} + +100 continue +end diff --git a/test/Sema/do.f95 b/test/Sema/do.f95 index ebe5f50341..ac6accbdbf 100644 --- a/test/Sema/do.f95 +++ b/test/Sema/do.f95 @@ -12,20 +12,19 @@ PROGRAM dotest R = I * R 10 CONTINUE ! expected-note {{previous definition is here}} - END DO ! expected-error {{use of 'END DO' without the do statement}} + END DO ! expected-error {{use of 'end do' outside a do construct}} DO 10 I = 1, 5 ! expected-error {{the statement label '10' must be declared after the 'DO' statement}} 20 R = R * R DO 25 II = 1, 10 - IF(.true.) THEN -25 CONTINUE ! expected-error {{expected 'END IF'}} - END IF + IF(.true.) THEN ! expected-note {{to match this 'if'}} +25 CONTINUE ! expected-error {{expected 'end if'}} DO 666 I = 1, 10,2 ! expected-error {{use of undeclared statement label '666'}} - R = I * R - - END DO ! expected-error {{expected a statement with a statement label '666' to mark the end of a do loop}} + R = I * R ! expected-note@-1 {{to match this 'do'}} + END DO ! expected-error {{expected a do termination statement with a statement label '666'}} + CONTINUE ! expected-error@-1 {{use of 'end do' outside a do construct}} DO 30 C = 1, 3 ! expected-error {{statement requires an integer variable ('complex' invalid)}} 30 CONTINUE diff --git a/test/Sema/dowhile.f95 b/test/Sema/dowhile.f95 index 938a3c2fee..6583c6de3b 100644 --- a/test/Sema/dowhile.f95 +++ b/test/Sema/dowhile.f95 @@ -8,8 +8,8 @@ PROGRAM dowhiletest END DO IF(.true.) THEN - DO WHILE(.false.) + DO WHILE(.false.) ! expected-note {{to match this 'do'}} - END IF ! expected-error {{expected 'END DO'}} + END IF ! expected-error {{expected 'end do'}} -END ! expected-error {{expected 'END DO'}} +END diff --git a/test/Sema/if.f95 b/test/Sema/if.f95 index e5b8e40b5a..679711c6bc 100644 --- a/test/Sema/if.f95 +++ b/test/Sema/if.f95 @@ -10,9 +10,9 @@ PROGRAM iftest I = 2 END IF - ELSE ! expected-error {{'ELSE' statement must be a part of an if construct}} - ELSE IF(2 == 2) THEN ! expected-error {{'ELSE IF' statement must be a part of an if construct}} - END IF ! expected-error {{'END IF' statement must be a part of an if construct}} + ELSE ! expected-error {{use of 'else' outside an if construct}} + ELSE IF(2 == 2) THEN ! expected-error {{use of 'else if' outside an if construct}} + END IF ! FIXME: report as out of place end if? IF(2) THEN ! expected-error {{statement requires an expression of logical type ('integer' invalid)}} I = 3 @@ -28,8 +28,4 @@ PROGRAM iftest I = 3 END IF - IF(.true.) THEN - DO I = 1, 10 - END IF ! expected-error {{expected 'END DO'}} - -END PROGRAM ! expected-error {{expected 'END DO'}} +END PROGRAM diff --git a/test/Sema/subprogram.f95 b/test/Sema/subprogram.f95 index fd21665569..88d51a68ab 100644 --- a/test/Sema/subprogram.f95 +++ b/test/Sema/subprogram.f95 @@ -22,8 +22,9 @@ END SUBROUTINE SUBB ! expected-note {{previous definition is here}} INTEGER SUBB ! expected-error {{redefinition of 'subb'}} REAL FUNC2 - IF(SUBB .EQ. 0) FUNC2 = 0 ! expected-error {{expected a variable}} -END ! expected-error {{expected 'END IF'}} + LOGICAL L + L = SUBB .EQ. 0 ! expected-error {{expected a variable}} +END FUNCTION FUNC3() INTEGER FUNC3 |