forked from OSchip/llvm-project
[flang] Fix parsing error on PROCEDURE statement in derived type definition.
Improve error recovery in that context. Original-commit: flang-compiler/f18@b9e48504e6 Reviewed-on: https://github.com/flang-compiler/f18/pull/21
This commit is contained in:
parent
a4a355940c
commit
1b0705ca0f
|
@ -78,6 +78,9 @@ They are `constexpr`, so they should be viewed as type-safe macros.
|
|||
* `deprecated(p)` parses p if strict standard compliance is disabled,
|
||||
with a warning if deprecated usage warnings are enabled.
|
||||
* `inContext(..., p)` runs p within an error message context.
|
||||
* `recovery(p, q)` is equivalent to `p || q`, except that error messages
|
||||
generated from the first parser are retained, and a flag is set in
|
||||
the ParseState to remember that error recovery was necessary.
|
||||
|
||||
Note that
|
||||
```
|
||||
|
|
|
@ -193,6 +193,20 @@ template<typename PA> inline constexpr auto statement(const PA &p) {
|
|||
return unterminatedStatement(p) / endOfStmt;
|
||||
}
|
||||
|
||||
// Error recovery within statements: skip to the end of the line,
|
||||
// but not over an END or CONTAINS statement.
|
||||
constexpr auto skipToEndOfLine = SkipTo<'\n'>{} >> construct<ErrorRecovery>{};
|
||||
constexpr auto stmtErrorRecovery =
|
||||
!"END"_tok >> !"CONTAINS"_tok >> skipToEndOfLine;
|
||||
|
||||
// Error recovery across statements: skip the line, unless it looks
|
||||
// like it might end the containing construct.
|
||||
constexpr auto errorRecoveryStart = skipMany("\n"_tok) >> maybe(label);
|
||||
constexpr auto skipBadLine = SkipPast<'\n'>{} >> construct<ErrorRecovery>{};
|
||||
constexpr auto executionPartErrorRecovery = errorRecoveryStart >> !"END"_tok >>
|
||||
!"ELSE"_tok >> !"CONTAINS"_tok >> !"CASE"_tok >> !"TYPE IS"_tok >>
|
||||
!"CLASS"_tok >> !"RANK"_tok >> skipBadLine;
|
||||
|
||||
// R507 declaration-construct ->
|
||||
// specification-construct | data-stmt | format-stmt |
|
||||
// entry-stmt | stmt-function-stmt
|
||||
|
@ -536,11 +550,6 @@ constexpr auto executableConstruct =
|
|||
construct<ExecutableConstruct>{}(indirect(whereConstruct)) ||
|
||||
construct<ExecutableConstruct>{}(indirect(forallConstruct));
|
||||
|
||||
constexpr auto executionPartErrorRecovery = skipMany("\n"_tok) >>
|
||||
maybe(label) >> !"END"_tok >> !"ELSE"_tok >> !"CONTAINS"_tok >>
|
||||
!"CASE"_tok >> !"TYPE IS"_tok >> !"CLASS"_tok >>
|
||||
!"RANK"_tok >> SkipPast<'\n'>{} >> construct<ErrorRecovery>{};
|
||||
|
||||
// R510 execution-part-construct ->
|
||||
// executable-construct | format-stmt | entry-stmt | data-stmt
|
||||
// Extension (PGI/Intel): also accept NAMELIST in execution part
|
||||
|
@ -903,14 +912,13 @@ TYPE_PARSER(
|
|||
construct<TypeParamDecl>{}(name, maybe("=" >> scalarIntConstantExpr)))
|
||||
|
||||
// R736 component-def-stmt -> data-component-def-stmt |
|
||||
// proc-component-def-stmt
|
||||
TYPE_PARSER(construct<ComponentDefStmt>{}(Parser<DataComponentDefStmt>{}) ||
|
||||
construct<ComponentDefStmt>{}(Parser<ProcComponentDefStmt>{})
|
||||
// Accidental extension: PGI accepts type-param-def-stmt in
|
||||
// component-part of derived-type-def. Not enabled here.
|
||||
// ||
|
||||
// extension(construct<ComponentDefStmt>{}(Parser<TypeParamDefStmt>{})
|
||||
)
|
||||
// proc-component-def-stmt
|
||||
// Accidental extension not enabled here: PGI accepts type-param-def-stmt in
|
||||
// component-part of derived-type-def.
|
||||
TYPE_PARSER(
|
||||
recovery(construct<ComponentDefStmt>{}(Parser<DataComponentDefStmt>{}) ||
|
||||
construct<ComponentDefStmt>{}(Parser<ProcComponentDefStmt>{}),
|
||||
construct<ComponentDefStmt>{}(stmtErrorRecovery)))
|
||||
|
||||
// R737 data-component-def-stmt ->
|
||||
// declaration-type-spec [[, component-attr-spec-list] ::]
|
||||
|
@ -996,10 +1004,11 @@ TYPE_CONTEXT_PARSER("type bound procedure part"_en_US,
|
|||
// R748 type-bound-proc-binding ->
|
||||
// type-bound-procedure-stmt | type-bound-generic-stmt |
|
||||
// final-procedure-stmt
|
||||
TYPE_PARSER(
|
||||
TYPE_PARSER(recovery(
|
||||
construct<TypeBoundProcBinding>{}(Parser<TypeBoundProcedureStmt>{}) ||
|
||||
construct<TypeBoundProcBinding>{}(Parser<TypeBoundGenericStmt>{}) ||
|
||||
construct<TypeBoundProcBinding>{}(Parser<FinalProcedureStmt>{}))
|
||||
construct<TypeBoundProcBinding>{}(Parser<TypeBoundGenericStmt>{}) ||
|
||||
construct<TypeBoundProcBinding>{}(Parser<FinalProcedureStmt>{}),
|
||||
construct<TypeBoundProcBinding>{}(stmtErrorRecovery)))
|
||||
|
||||
// R749 type-bound-procedure-stmt ->
|
||||
// PROCEDURE [[, bind-attr-list] ::] type-bound-proc-decl-list |
|
||||
|
@ -3384,8 +3393,8 @@ TYPE_PARSER("PROCEDURE" >>
|
|||
|
||||
// R1513 proc-interface -> interface-name | declaration-type-spec
|
||||
// R1516 interface-name -> name
|
||||
TYPE_PARSER(construct<ProcInterface>{}(name) ||
|
||||
construct<ProcInterface>{}(declarationTypeSpec))
|
||||
TYPE_PARSER(construct<ProcInterface>{}(declarationTypeSpec) ||
|
||||
construct<ProcInterface>{}(name))
|
||||
|
||||
// R1514 proc-attr-spec ->
|
||||
// access-spec | proc-language-binding-spec | INTENT ( intent-spec ) |
|
||||
|
|
|
@ -154,6 +154,13 @@ public:
|
|||
return {ch};
|
||||
}
|
||||
|
||||
std::optional<char> PeekAtNextChar() {
|
||||
if (p_ >= limit_) {
|
||||
return {};
|
||||
}
|
||||
return {*p_};
|
||||
}
|
||||
|
||||
private:
|
||||
// Text remaining to be parsed
|
||||
const CookedSource &cooked_;
|
||||
|
|
|
@ -973,7 +973,7 @@ struct ProcComponentDefStmt {
|
|||
// R736 component-def-stmt -> data-component-def-stmt | proc-component-def-stmt
|
||||
struct ComponentDefStmt {
|
||||
UNION_CLASS_BOILERPLATE(ComponentDefStmt);
|
||||
std::variant<DataComponentDefStmt, ProcComponentDefStmt
|
||||
std::variant<DataComponentDefStmt, ProcComponentDefStmt, ErrorRecovery
|
||||
// , TypeParamDefStmt -- PGI accidental extension, not enabled
|
||||
>
|
||||
u;
|
||||
|
@ -1036,7 +1036,8 @@ WRAPPER_CLASS(FinalProcedureStmt, std::list<Name>);
|
|||
// final-procedure-stmt
|
||||
struct TypeBoundProcBinding {
|
||||
UNION_CLASS_BOILERPLATE(TypeBoundProcBinding);
|
||||
std::variant<TypeBoundProcedureStmt, TypeBoundGenericStmt, FinalProcedureStmt>
|
||||
std::variant<TypeBoundProcedureStmt, TypeBoundGenericStmt, FinalProcedureStmt,
|
||||
ErrorRecovery>
|
||||
u;
|
||||
};
|
||||
|
||||
|
|
|
@ -404,6 +404,21 @@ template<char goal> struct SkipPast {
|
|||
}
|
||||
};
|
||||
|
||||
template<char goal> struct SkipTo {
|
||||
using resultType = Success;
|
||||
constexpr SkipTo() {}
|
||||
constexpr SkipTo(const SkipTo &) {}
|
||||
static std::optional<Success> Parse(ParseState *state) {
|
||||
while (std::optional<char> ch{state->PeekAtNextChar()}) {
|
||||
if (*ch == goal) {
|
||||
return {Success{}};
|
||||
}
|
||||
state->GetNextChar();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
// A common idiom in the Fortran grammar is an optional item (usually
|
||||
// a nonempty comma-separated list) that, if present, must follow a comma
|
||||
// and precede a doubled colon. When the item is absent, the comma must
|
||||
|
|
|
@ -236,6 +236,7 @@ static void visitDerivedTypeDef(const DerivedTypeDef &dtd) {
|
|||
[&](const ProcComponentDefStmt &x) {
|
||||
TODO("ProcComponentDefStmt");
|
||||
},
|
||||
[&](const ErrorRecovery &) {},
|
||||
},
|
||||
cds.statement.u);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue