[flang-commits] [flang] 2d8b6a4 - [flang] Add explanatory messages to grammar for language extensions

Peter Klausler via flang-commits flang-commits at lists.llvm.org
Fri Mar 18 16:14:34 PDT 2022


Author: Peter Klausler
Date: 2022-03-18T16:14:27-07:00
New Revision: 2d8b6a478496ff1ecb9276ac91788f7a94885428

URL: https://github.com/llvm/llvm-project/commit/2d8b6a478496ff1ecb9276ac91788f7a94885428
DIFF: https://github.com/llvm/llvm-project/commit/2d8b6a478496ff1ecb9276ac91788f7a94885428.diff

LOG: [flang] Add explanatory messages to grammar for language extensions

Extend "extension<LanguageFeature>()" to incorporate an explanatory
message better than the current generic "nonstandard usage:".

Differential Revision: https://reviews.llvm.org/D122035

Added: 
    

Modified: 
    flang/lib/Parser/Fortran-parsers.cpp
    flang/lib/Parser/basic-parsers.h
    flang/lib/Parser/executable-parsers.cpp
    flang/lib/Parser/expr-parsers.cpp
    flang/lib/Parser/io-parsers.cpp
    flang/lib/Parser/program-parsers.cpp
    flang/lib/Parser/token-parsers.h

Removed: 
    


################################################################################
diff  --git a/flang/lib/Parser/Fortran-parsers.cpp b/flang/lib/Parser/Fortran-parsers.cpp
index 4e5555ea1f64d..39dbd2c3179ab 100644
--- a/flang/lib/Parser/Fortran-parsers.cpp
+++ b/flang/lib/Parser/Fortran-parsers.cpp
@@ -65,13 +65,16 @@ constexpr auto namedIntrinsicOperator{
     ".EQV." >> pure(DefinedOperator::IntrinsicOperator::EQV) ||
     ".NEQV." >> pure(DefinedOperator::IntrinsicOperator::NEQV) ||
     extension<LanguageFeature::XOROperator>(
+        "nonstandard usage: .XOR. spelling of .NEQV."_port_en_US,
         ".XOR." >> pure(DefinedOperator::IntrinsicOperator::NEQV)) ||
     extension<LanguageFeature::LogicalAbbreviations>(
+        "nonstandard usage: abbreviated logical operator"_port_en_US,
         ".N." >> pure(DefinedOperator::IntrinsicOperator::NOT) ||
-        ".A." >> pure(DefinedOperator::IntrinsicOperator::AND) ||
-        ".O." >> pure(DefinedOperator::IntrinsicOperator::OR) ||
-        extension<LanguageFeature::XOROperator>(
-            ".X." >> pure(DefinedOperator::IntrinsicOperator::NEQV)))};
+            ".A." >> pure(DefinedOperator::IntrinsicOperator::AND) ||
+            ".O." >> pure(DefinedOperator::IntrinsicOperator::OR) ||
+            extension<LanguageFeature::XOROperator>(
+                "nonstandard usage: .X. spelling of .NEQV."_port_en_US,
+                ".X." >> pure(DefinedOperator::IntrinsicOperator::NEQV)))};
 
 constexpr auto intrinsicOperator{
     "**" >> pure(DefinedOperator::IntrinsicOperator::Power) ||
@@ -83,6 +86,7 @@ constexpr auto intrinsicOperator{
     "-" >> pure(DefinedOperator::IntrinsicOperator::Subtract) ||
     "<=" >> pure(DefinedOperator::IntrinsicOperator::LE) ||
     extension<LanguageFeature::AlternativeNE>(
+        "nonstandard usage: <> spelling of /= or .NE."_port_en_US,
         "<>" >> pure(DefinedOperator::IntrinsicOperator::NE)) ||
     "<" >> pure(DefinedOperator::IntrinsicOperator::LT) ||
     "==" >> pure(DefinedOperator::IntrinsicOperator::EQ) ||
@@ -178,6 +182,7 @@ TYPE_CONTEXT_PARSER("declaration type spec"_en_US,
                        construct<DeclarationTypeSpec>("*" >>
                            construct<DeclarationTypeSpec::ClassStar>())) ||
         extension<LanguageFeature::DECStructures>(
+            "nonstandard usage: STRUCTURE"_port_en_US,
             construct<DeclarationTypeSpec>(
                 // As is also done for the STRUCTURE statement, the name of
                 // the structure includes the surrounding slashes to avoid
@@ -202,9 +207,11 @@ TYPE_CONTEXT_PARSER("intrinsic type spec"_en_US,
             "CHARACTER" >> maybe(Parser<CharSelector>{}))),
         construct<IntrinsicTypeSpec>(construct<IntrinsicTypeSpec::Logical>(
             "LOGICAL" >> maybe(kindSelector))),
-        extension<LanguageFeature::DoubleComplex>(construct<IntrinsicTypeSpec>(
-            "DOUBLE COMPLEX" >> construct<IntrinsicTypeSpec::DoubleComplex>())),
-        extension<LanguageFeature::Byte>(
+        extension<LanguageFeature::DoubleComplex>(
+            "nonstandard usage: DOUBLE COMPLEX"_port_en_US,
+            construct<IntrinsicTypeSpec>("DOUBLE COMPLEX" >>
+                construct<IntrinsicTypeSpec::DoubleComplex>())),
+        extension<LanguageFeature::Byte>("nonstandard usage: BYTE"_port_en_US,
             construct<IntrinsicTypeSpec>(construct<IntegerTypeSpec>(
                 "BYTE" >> construct<std::optional<KindSelector>>(pure(1)))))))
 
@@ -215,8 +222,10 @@ TYPE_PARSER(construct<IntegerTypeSpec>("INTEGER" >> maybe(kindSelector)))
 // Legacy extension: kind-selector -> * digit-string
 TYPE_PARSER(construct<KindSelector>(
                 parenthesized(maybe("KIND ="_tok) >> scalarIntConstantExpr)) ||
-    extension<LanguageFeature::StarKind>(construct<KindSelector>(
-        construct<KindSelector::StarSize>("*" >> digitString64 / spaceCheck))))
+    extension<LanguageFeature::StarKind>(
+        "nonstandard usage: TYPE*KIND syntax"_port_en_US,
+        construct<KindSelector>(construct<KindSelector::StarSize>(
+            "*" >> digitString64 / spaceCheck))))
 
 // R707 signed-int-literal-constant -> [sign] int-literal-constant
 TYPE_PARSER(sourced(construct<SignedIntLiteralConstant>(
@@ -251,7 +260,9 @@ constexpr auto signedRealLiteralConstant{
 // Extension: Q
 // R717 exponent -> signed-digit-string
 constexpr auto exponentPart{
-    ("ed"_ch || extension<LanguageFeature::QuadPrecision>("q"_ch)) >>
+    ("ed"_ch ||
+        extension<LanguageFeature::QuadPrecision>(
+            "nonstandard usage: Q exponent"_port_en_US, "q"_ch)) >>
     SignedDigitString{}};
 
 TYPE_CONTEXT_PARSER("REAL literal constant"_en_US,
@@ -431,6 +442,7 @@ TYPE_CONTEXT_PARSER("component declaration"_en_US,
 // The source field of the Name will be replaced with a distinct generated name.
 TYPE_CONTEXT_PARSER("%FILL item"_en_US,
     extension<LanguageFeature::DECStructures>(
+        "nonstandard usage: %FILL"_port_en_US,
         construct<FillDecl>(space >> sourced("%FILL" >> construct<Name>()),
             maybe(Parser<ComponentArraySpec>{}), maybe("*" >> charLength))))
 TYPE_PARSER(construct<ComponentOrFill>(Parser<ComponentDecl>{}) ||
@@ -475,10 +487,12 @@ constexpr auto initialDataTarget{indirect(designator)};
 TYPE_PARSER(construct<Initialization>("=>" >> nullInit) ||
     construct<Initialization>("=>" >> initialDataTarget) ||
     construct<Initialization>("=" >> constantExpr) ||
-    extension<LanguageFeature::SlashInitialization>(construct<Initialization>(
-        "/" >> nonemptyList("expected values"_err_en_US,
-                   indirect(Parser<DataStmtValue>{})) /
-            "/")))
+    extension<LanguageFeature::SlashInitialization>(
+        "nonstandard usage: /initialization/"_port_en_US,
+        construct<Initialization>(
+            "/" >> nonemptyList("expected values"_err_en_US,
+                       indirect(Parser<DataStmtValue>{})) /
+                "/")))
 
 // R745 private-components-stmt -> PRIVATE
 // R747 binding-private-stmt -> PRIVATE
@@ -608,10 +622,12 @@ TYPE_PARSER(
         nonemptyList("expected entity declarations"_err_en_US,
             entityDeclWithoutEqInit)) ||
     // PGI-only extension: comma in place of doubled colons
-    extension<LanguageFeature::MissingColons>(construct<TypeDeclarationStmt>(
-        declarationTypeSpec, defaulted("," >> nonemptyList(Parser<AttrSpec>{})),
-        withMessage("expected entity declarations"_err_en_US,
-            "," >> nonemptyList(entityDecl)))))
+    extension<LanguageFeature::MissingColons>(
+        "nonstandard usage: ',' in place of '::'"_port_en_US,
+        construct<TypeDeclarationStmt>(declarationTypeSpec,
+            defaulted("," >> nonemptyList(Parser<AttrSpec>{})),
+            withMessage("expected entity declarations"_err_en_US,
+                "," >> nonemptyList(entityDecl)))))
 
 // R802 attr-spec ->
 //        access-spec | ALLOCATABLE | ASYNCHRONOUS |
@@ -841,6 +857,7 @@ TYPE_PARSER(sourced(first(construct<DataStmtConstant>(literalConstant),
     construct<DataStmtConstant>(signedRealLiteralConstant),
     construct<DataStmtConstant>(signedIntLiteralConstant),
     extension<LanguageFeature::SignedComplexLiteral>(
+        "nonstandard usage: signed COMPLEX literal"_port_en_US,
         construct<DataStmtConstant>(Parser<SignedComplexLiteralConstant>{})),
     construct<DataStmtConstant>(nullInit),
     construct<DataStmtConstant>(indirect(designator) / !"("_tok),
@@ -869,8 +886,10 @@ TYPE_CONTEXT_PARSER("PARAMETER statement"_en_US,
     construct<ParameterStmt>(
         "PARAMETER" >> parenthesized(nonemptyList(Parser<NamedConstantDef>{}))))
 TYPE_CONTEXT_PARSER("old style PARAMETER statement"_en_US,
-    extension<LanguageFeature::OldStyleParameter>(construct<OldParameterStmt>(
-        "PARAMETER" >> nonemptyList(Parser<NamedConstantDef>{}))))
+    extension<LanguageFeature::OldStyleParameter>(
+        "nonstandard usage: PARAMETER without parentheses"_port_en_US,
+        construct<OldParameterStmt>(
+            "PARAMETER" >> nonemptyList(Parser<NamedConstantDef>{}))))
 
 // R852 named-constant-def -> named-constant = constant-expr
 TYPE_PARSER(construct<NamedConstantDef>(namedConstant, "=" >> constantExpr))
@@ -1024,6 +1043,7 @@ TYPE_CONTEXT_PARSER("designator"_en_US,
 constexpr auto percentOrDot{"%"_tok ||
     // legacy VAX extension for RECORD field access
     extension<LanguageFeature::DECStructures>(
+        "nonstandard usage: component access with '.' in place of '%'"_port_en_US,
         "."_tok / lookAhead(OldStructureComponentName{}))};
 
 // R902 variable -> designator | function-reference
@@ -1184,10 +1204,12 @@ TYPE_PARSER(beginDirective >>
                           maybe(("="_tok || ":"_tok) >> digitString64))))) /
         endDirective)
 
-TYPE_PARSER(extension<LanguageFeature::CrayPointer>(construct<BasedPointerStmt>(
-    "POINTER" >> nonemptyList("expected POINTER associations"_err_en_US,
-                     construct<BasedPointer>("(" >> objectName / ",",
-                         objectName, maybe(Parser<ArraySpec>{}) / ")")))))
+TYPE_PARSER(extension<LanguageFeature::CrayPointer>(
+    "nonstandard usage: based POINTER"_port_en_US,
+    construct<BasedPointerStmt>(
+        "POINTER" >> nonemptyList("expected POINTER associations"_err_en_US,
+                         construct<BasedPointer>("(" >> objectName / ",",
+                             objectName, maybe(Parser<ArraySpec>{}) / ")")))))
 
 // Subtle: the name includes the surrounding slashes, which avoids
 // clashes with other uses of the name in the same scope.
@@ -1206,10 +1228,12 @@ TYPE_PARSER(construct<StructureField>(statement(StructureComponents{})) ||
     construct<StructureField>(indirect(nestedStructureDef)))
 
 TYPE_CONTEXT_PARSER("STRUCTURE definition"_en_US,
-    extension<LanguageFeature::DECStructures>(construct<StructureDef>(
-        statement(Parser<StructureStmt>{}), many(Parser<StructureField>{}),
-        statement(
-            construct<StructureDef::EndStructureStmt>("END STRUCTURE"_tok)))))
+    extension<LanguageFeature::DECStructures>(
+        "nonstandard usage: STRUCTURE"_port_en_US,
+        construct<StructureDef>(statement(Parser<StructureStmt>{}),
+            many(Parser<StructureField>{}),
+            statement(construct<StructureDef::EndStructureStmt>(
+                "END STRUCTURE"_tok)))))
 
 TYPE_CONTEXT_PARSER("UNION definition"_en_US,
     construct<Union>(statement(construct<Union::UnionStmt>("UNION"_tok)),

diff  --git a/flang/lib/Parser/basic-parsers.h b/flang/lib/Parser/basic-parsers.h
index 0404f9e2bed36..e2355a7526ae8 100644
--- a/flang/lib/Parser/basic-parsers.h
+++ b/flang/lib/Parser/basic-parsers.h
@@ -845,7 +845,8 @@ template <LanguageFeature LF, typename PA> class NonstandardParser {
 public:
   using resultType = typename PA::resultType;
   constexpr NonstandardParser(const NonstandardParser &) = default;
-  constexpr NonstandardParser(PA parser) : parser_{parser} {}
+  constexpr NonstandardParser(PA parser, MessageFixedText msg)
+      : parser_{parser}, message_{msg} {}
   std::optional<resultType> Parse(ParseState &state) const {
     if (UserState * ustate{state.userState()}) {
       if (!ustate->features().IsEnabled(LF)) {
@@ -855,19 +856,20 @@ template <LanguageFeature LF, typename PA> class NonstandardParser {
     auto at{state.GetLocation()};
     auto result{parser_.Parse(state)};
     if (result) {
-      state.Nonstandard(CharBlock{at, std::max(state.GetLocation(), at + 1)},
-          LF, "nonstandard usage"_port_en_US);
+      state.Nonstandard(
+          CharBlock{at, std::max(state.GetLocation(), at + 1)}, LF, message_);
     }
     return result;
   }
 
 private:
   const PA parser_;
+  const MessageFixedText message_;
 };
 
 template <LanguageFeature LF, typename PA>
-inline constexpr auto extension(PA parser) {
-  return NonstandardParser<LF, PA>(parser);
+inline constexpr auto extension(MessageFixedText feature, PA parser) {
+  return NonstandardParser<LF, PA>(parser, feature);
 }
 
 // If a is a parser for some deprecated or deleted language feature LF,

diff  --git a/flang/lib/Parser/executable-parsers.cpp b/flang/lib/Parser/executable-parsers.cpp
index 66b217a698fdd..04fe1849a6fd5 100644
--- a/flang/lib/Parser/executable-parsers.cpp
+++ b/flang/lib/Parser/executable-parsers.cpp
@@ -76,6 +76,7 @@ TYPE_PARSER(recovery(
                 construct<ExecutionPartConstruct>(
                     statement(indirect(dataStmt))),
                 extension<LanguageFeature::ExecutionPartNamelist>(
+                    "nonstandard usage: NAMELIST in execution part"_port_en_US,
                     construct<ExecutionPartConstruct>(
                         statement(indirect(Parser<NamelistStmt>{})))),
                 obsoleteExecutionPartConstruct))),

diff  --git a/flang/lib/Parser/expr-parsers.cpp b/flang/lib/Parser/expr-parsers.cpp
index 0743e120025b1..e0a55b138be79 100644
--- a/flang/lib/Parser/expr-parsers.cpp
+++ b/flang/lib/Parser/expr-parsers.cpp
@@ -44,6 +44,7 @@ TYPE_PARSER(construct<AcSpec>(maybe(typeSpec / "::"),
 TYPE_PARSER(
     // PGI/Intel extension: accept triplets in array constructors
     extension<LanguageFeature::TripletInArrayConstructor>(
+        "nonstandard usage: triplet in array constructor"_port_en_US,
         construct<AcValue>(construct<AcValue::Triplet>(scalarIntExpr,
             ":" >> scalarIntExpr, maybe(":" >> scalarIntExpr)))) ||
     construct<AcValue>(indirect(expr)) ||
@@ -76,10 +77,13 @@ constexpr auto primary{instrumented("primary"_en_US,
         construct<Expr>(Parser<ArrayConstructor>{}),
         // PGI/XLF extension: COMPLEX constructor (x,y)
         extension<LanguageFeature::ComplexConstructor>(
+            "nonstandard usage: generalized COMPLEX constructor"_port_en_US,
             construct<Expr>(parenthesized(
                 construct<Expr::ComplexConstructor>(expr, "," >> expr)))),
-        extension<LanguageFeature::PercentLOC>(construct<Expr>("%LOC" >>
-            parenthesized(construct<Expr::PercentLoc>(indirect(variable)))))))};
+        extension<LanguageFeature::PercentLOC>(
+            "nonstandard usage: %LOC"_port_en_US,
+            construct<Expr>("%LOC" >> parenthesized(construct<Expr::PercentLoc>(
+                                          indirect(variable)))))))};
 
 // R1002 level-1-expr -> [defined-unary-op] primary
 // TODO: Reasonable extension: permit multiple defined-unary-ops
@@ -87,8 +91,10 @@ constexpr auto level1Expr{sourced(
     first(primary, // must come before define op to resolve .TRUE._8 ambiguity
         construct<Expr>(construct<Expr::DefinedUnary>(definedOpName, primary)),
         extension<LanguageFeature::SignedPrimary>(
+            "nonstandard usage: signed primary"_port_en_US,
             construct<Expr>(construct<Expr::UnaryPlus>("+" >> primary))),
         extension<LanguageFeature::SignedPrimary>(
+            "nonstandard usage: signed primary"_port_en_US,
             construct<Expr>(construct<Expr::Negate>("-" >> primary)))))};
 
 // R1004 mult-operand -> level-1-expr [power-op mult-operand]
@@ -244,6 +250,7 @@ struct Level4Expr {
               (".EQ."_tok || "=="_tok) >> applyLambda(eq, level3Expr) ||
               (".NE."_tok || "/="_tok ||
                   extension<LanguageFeature::AlternativeNE>(
+                      "nonstandard usage: <> for /= or .NE."_port_en_US,
                       "<>"_tok /* PGI/Cray extension; Cray also has .LG. */)) >>
                   applyLambda(ne, level3Expr) ||
               (".GE."_tok || ">="_tok) >> applyLambda(ge, level3Expr) ||
@@ -273,6 +280,7 @@ constexpr AndOperand andOperand;
 inline constexpr auto logicalOp(const char *op, const char *abbrev) {
   return TokenStringMatch{op} ||
       extension<LanguageFeature::LogicalAbbreviations>(
+          "nonstandard usage: abbreviated LOGICAL operator"_port_en_US,
           TokenStringMatch{abbrev});
 }
 
@@ -356,6 +364,7 @@ struct Level5Expr {
       auto more{attempt(sourced(".EQV." >> applyLambda(eqv, equivOperand) ||
           (".NEQV."_tok ||
               extension<LanguageFeature::XOROperator>(
+                  "nonstandard usage: .XOR./.X. spelling of .NEQV."_port_en_US,
                   logicalOp(".XOR.", ".X."))) >>
               applyLambda(neqv, equivOperand)))};
       while (std::optional<Expr> next{more.Parse(state)}) {
@@ -397,8 +406,10 @@ template <> std::optional<Expr> Parser<Expr>::Parse(ParseState &state) {
 // and intrinsic operator names; this is handled by attempting their parses
 // first, and by name resolution on their definitions, for best errors.
 // N.B. The name of the operator is captured with the dots around it.
-constexpr auto definedOpNameChar{
-    letter || extension<LanguageFeature::PunctuationInNames>("$@"_ch)};
+constexpr auto definedOpNameChar{letter ||
+    extension<LanguageFeature::PunctuationInNames>(
+        "nonstandard usage: non-alphabetic character in defined operator"_port_en_US,
+        "$@"_ch)};
 TYPE_PARSER(
     space >> construct<DefinedOpName>(sourced("."_ch >>
                  some(definedOpNameChar) >> construct<Name>() / "."_ch)))

diff  --git a/flang/lib/Parser/io-parsers.cpp b/flang/lib/Parser/io-parsers.cpp
index a4cf6971daf39..2296d84d58f0f 100644
--- a/flang/lib/Parser/io-parsers.cpp
+++ b/flang/lib/Parser/io-parsers.cpp
@@ -85,6 +85,7 @@ TYPE_PARSER(first(construct<ConnectSpec>(maybe("UNIT ="_tok) >> fileUnitNumber),
     construct<ConnectSpec>("ERR =" >> errLabel),
     construct<ConnectSpec>("FILE =" >> fileNameExpr),
     extension<LanguageFeature::FileName>(
+        "nonstandard usage: NAME= in place of FILE="_port_en_US,
         construct<ConnectSpec>("NAME =" >> fileNameExpr)),
     construct<ConnectSpec>(construct<ConnectSpec::CharExpr>(
         "FORM =" >> pure(ConnectSpec::CharExpr::Kind::Form),
@@ -108,15 +109,19 @@ TYPE_PARSER(first(construct<ConnectSpec>(maybe("UNIT ="_tok) >> fileUnitNumber),
         "SIGN =" >> pure(ConnectSpec::CharExpr::Kind::Sign),
         scalarDefaultCharExpr)),
     construct<ConnectSpec>("STATUS =" >> statusExpr),
-    extension<LanguageFeature::Carriagecontrol>(construct<ConnectSpec>(
-        construct<ConnectSpec::CharExpr>("CARRIAGECONTROL =" >>
-                pure(ConnectSpec::CharExpr::Kind::Carriagecontrol),
-            scalarDefaultCharExpr))),
+    extension<LanguageFeature::Carriagecontrol>(
+        "nonstandard usage: CARRIAGECONTROL="_port_en_US,
+        construct<ConnectSpec>(
+            construct<ConnectSpec::CharExpr>("CARRIAGECONTROL =" >>
+                    pure(ConnectSpec::CharExpr::Kind::Carriagecontrol),
+                scalarDefaultCharExpr))),
     extension<LanguageFeature::Convert>(
+        "nonstandard usage: CONVERT="_port_en_US,
         construct<ConnectSpec>(construct<ConnectSpec::CharExpr>(
             "CONVERT =" >> pure(ConnectSpec::CharExpr::Kind::Convert),
             scalarDefaultCharExpr))),
     extension<LanguageFeature::Dispose>(
+        "nonstandard usage: DISPOSE="_port_en_US,
         construct<ConnectSpec>(construct<ConnectSpec::CharExpr>(
             "DISPOSE =" >> pure(ConnectSpec::CharExpr::Kind::Dispose),
             scalarDefaultCharExpr)))))
@@ -145,6 +150,7 @@ TYPE_CONTEXT_PARSER("CLOSE statement"_en_US,
 // rewriting in semantics when we know that CVAR is character.
 constexpr auto inputItemList{
     extension<LanguageFeature::IOListLeadingComma>(
+        "nonstandard usage: leading comma in input item list"_port_en_US,
         some("," >> inputItem)) || // legacy extension: leading comma
     optionalList(inputItem)};
 
@@ -226,6 +232,7 @@ TYPE_PARSER(first(construct<IoControlSpec>("UNIT =" >> ioUnit),
 // R1211 write-stmt -> WRITE ( io-control-spec-list ) [output-item-list]
 constexpr auto outputItemList{
     extension<LanguageFeature::IOListLeadingComma>(
+        "nonstandard usage: leading comma in output item list"_port_en_US,
         some("," >> outputItem)) || // legacy: allow leading comma
     optionalList(outputItem)};
 
@@ -486,18 +493,23 @@ TYPE_PARSER(first(construct<InquireSpec>(maybe("UNIT ="_tok) >> fileUnitNumber),
         construct<InquireSpec::CharVar>(pure(InquireSpec::CharVar::Kind::Write),
             scalarDefaultCharVariable)),
     extension<LanguageFeature::Carriagecontrol>(
+        "nonstandard usage: CARRIAGECONTROL="_port_en_US,
         construct<InquireSpec>("CARRIAGECONTROL =" >>
             construct<InquireSpec::CharVar>(
                 pure(InquireSpec::CharVar::Kind::Carriagecontrol),
                 scalarDefaultCharVariable))),
-    extension<LanguageFeature::Convert>(construct<InquireSpec>(
-        "CONVERT =" >> construct<InquireSpec::CharVar>(
-                           pure(InquireSpec::CharVar::Kind::Convert),
-                           scalarDefaultCharVariable))),
-    extension<LanguageFeature::Dispose>(construct<InquireSpec>(
-        "DISPOSE =" >> construct<InquireSpec::CharVar>(
-                           pure(InquireSpec::CharVar::Kind::Dispose),
-                           scalarDefaultCharVariable)))))
+    extension<LanguageFeature::Convert>(
+        "nonstandard usage: CONVERT="_port_en_US,
+        construct<InquireSpec>(
+            "CONVERT =" >> construct<InquireSpec::CharVar>(
+                               pure(InquireSpec::CharVar::Kind::Convert),
+                               scalarDefaultCharVariable))),
+    extension<LanguageFeature::Dispose>(
+        "nonstandard usage: DISPOSE="_port_en_US,
+        construct<InquireSpec>(
+            "DISPOSE =" >> construct<InquireSpec::CharVar>(
+                               pure(InquireSpec::CharVar::Kind::Dispose),
+                               scalarDefaultCharVariable)))))
 
 // R1230 inquire-stmt ->
 //         INQUIRE ( inquire-spec-list ) |
@@ -591,6 +603,7 @@ TYPE_PARSER(construct<format::IntrinsicTypeDataEditDesc>(
         noInt, noInt) ||
     // PGI/Intel extension: omitting width (and all else that follows)
     extension<LanguageFeature::AbbreviatedEditDescriptor>(
+        "nonstandard usage: abbreviated edit descriptor"_port_en_US,
         construct<format::IntrinsicTypeDataEditDesc>(
             "I" >> pure(format::IntrinsicTypeDataEditDesc::Kind::I) ||
                 ("B"_tok / !letter /* don't occlude BN & BZ */) >>
@@ -673,8 +686,9 @@ TYPE_PARSER(construct<format::ControlEditDesc>(
                "P" >> construct<format::ControlEditDesc>(
                           pure(format::ControlEditDesc::Kind::DP))) ||
     extension<LanguageFeature::AdditionalFormats>(
+        "nonstandard usage: $ and \\ control edit descriptors"_port_en_US,
         "$" >> construct<format::ControlEditDesc>(
                    pure(format::ControlEditDesc::Kind::Dollar)) ||
-        "\\" >> construct<format::ControlEditDesc>(
-                    pure(format::ControlEditDesc::Kind::Backslash))))
+            "\\" >> construct<format::ControlEditDesc>(
+                        pure(format::ControlEditDesc::Kind::Backslash))))
 } // namespace Fortran::parser

diff  --git a/flang/lib/Parser/program-parsers.cpp b/flang/lib/Parser/program-parsers.cpp
index 6a2208484ab20..476be856fc713 100644
--- a/flang/lib/Parser/program-parsers.cpp
+++ b/flang/lib/Parser/program-parsers.cpp
@@ -54,11 +54,13 @@ static constexpr auto globalCompilerDirective{
 // Consequently, a program unit END statement should be the last statement
 // on its line.  We parse those END statements via unterminatedStatement()
 // and then skip over the end of the line here.
-TYPE_PARSER(construct<Program>(
-    extension<LanguageFeature::EmptySourceFile>(skipStuffBeforeStatement >>
-        !nextCh >> pure<std::list<ProgramUnit>>()) ||
-    some(globalCompilerDirective || normalProgramUnit) /
-        skipStuffBeforeStatement))
+TYPE_PARSER(
+    construct<Program>(extension<LanguageFeature::EmptySourceFile>(
+                           "nonstandard usage: empty source file"_port_en_US,
+                           skipStuffBeforeStatement >> !nextCh >>
+                               pure<std::list<ProgramUnit>>()) ||
+        some(globalCompilerDirective || normalProgramUnit) /
+            skipStuffBeforeStatement))
 
 // R504 specification-part ->
 //         [use-stmt]... [import-stmt]... [implicit-part]
@@ -204,6 +206,7 @@ TYPE_CONTEXT_PARSER("main program"_en_US,
 TYPE_CONTEXT_PARSER("PROGRAM statement"_en_US,
     construct<ProgramStmt>("PROGRAM" >> name /
             maybe(extension<LanguageFeature::ProgramParentheses>(
+                "nonstandard usage: parentheses in PROGRAM statement"_port_en_US,
                 parenthesized(ok)))))
 
 // R1403 end-program-stmt -> END [PROGRAM [program-name]]
@@ -449,10 +452,14 @@ TYPE_PARSER(construct<ActualArgSpec>(
 // Semantics sorts it all out later.
 TYPE_PARSER(construct<ActualArg>(expr) ||
     construct<ActualArg>(Parser<AltReturnSpec>{}) ||
-    extension<LanguageFeature::PercentRefAndVal>(construct<ActualArg>(
-        construct<ActualArg::PercentRef>("%REF" >> parenthesized(variable)))) ||
-    extension<LanguageFeature::PercentRefAndVal>(construct<ActualArg>(
-        construct<ActualArg::PercentVal>("%VAL" >> parenthesized(expr)))))
+    extension<LanguageFeature::PercentRefAndVal>(
+        "nonstandard usage: %REF"_port_en_US,
+        construct<ActualArg>(construct<ActualArg::PercentRef>(
+            "%REF" >> parenthesized(variable)))) ||
+    extension<LanguageFeature::PercentRefAndVal>(
+        "nonstandard usage: %VAL"_port_en_US,
+        construct<ActualArg>(
+            construct<ActualArg::PercentVal>("%VAL" >> parenthesized(expr)))))
 
 // R1525 alt-return-spec -> * label
 TYPE_PARSER(construct<AltReturnSpec>(star >> label))
@@ -485,6 +492,7 @@ TYPE_CONTEXT_PARSER("FUNCTION statement"_en_US,
     construct<FunctionStmt>(many(prefixSpec), "FUNCTION" >> name,
         parenthesized(optionalList(name)), maybe(suffix)) ||
         extension<LanguageFeature::OmitFunctionDummies>(
+            "nonstandard usage: FUNCTION statement without dummy argument list"_port_en_US,
             construct<FunctionStmt>( // PGI & Intel accept "FUNCTION F"
                 many(prefixSpec), "FUNCTION" >> name,
                 construct<std::list<Name>>(),

diff  --git a/flang/lib/Parser/token-parsers.h b/flang/lib/Parser/token-parsers.h
index be37f11d17d94..ff1ba334e73b4 100644
--- a/flang/lib/Parser/token-parsers.h
+++ b/flang/lib/Parser/token-parsers.h
@@ -655,15 +655,20 @@ constexpr auto underscore{"_"_ch};
 // Cray and gfortran accept '$', but not as the first character.
 // Cray accepts '@' as well.
 constexpr auto otherIdChar{underscore / !"'\""_ch ||
-    extension<LanguageFeature::PunctuationInNames>("$@"_ch)};
+    extension<LanguageFeature::PunctuationInNames>(
+        "nonstandard usage: punctuation in name"_port_en_US, "$@"_ch)};
 
 constexpr auto logicalTRUE{
     (".TRUE."_tok ||
-        extension<LanguageFeature::LogicalAbbreviations>(".T."_tok)) >>
+        extension<LanguageFeature::LogicalAbbreviations>(
+            "nonstandard usage: .T. spelling of .TRUE."_port_en_US,
+            ".T."_tok)) >>
     pure(true)};
 constexpr auto logicalFALSE{
     (".FALSE."_tok ||
-        extension<LanguageFeature::LogicalAbbreviations>(".F."_tok)) >>
+        extension<LanguageFeature::LogicalAbbreviations>(
+            "nonstandard usage: .F. spelling of .FALSE."_port_en_US,
+            ".F."_tok)) >>
     pure(false)};
 
 // deprecated: Hollerith literals


        


More information about the flang-commits mailing list