From ac77649951db17f1126bde08d580ec101f0759bc Mon Sep 17 00:00:00 2001 From: Peter Klausler Date: Fri, 1 Jul 2022 11:49:55 -0700 Subject: [PATCH] [flang] Avoid spurious warnings in pedantic mode from FORMAT items In free form source, pedantic mode will elicit portability warnings about missing spaces when a token string ends with a character that can be in an identifier and there is no space between that last token character and a following character that can also be part of an identifier. This behavior doesn't really work well for the token strings that are parsed for edit descriptors in FORMAT statements. For example, the 'F' in FORMAT(F7.3) is followed by a digit, but obviously no space is necessary. Free form or not, FORMATs are their own odd little world. This patch adds trailing blanks to these FORMAT edit descriptor token parsers to disable the missing space check, and extends the documentation for token string parsing to explain why this technique works. Differential Revision: https://reviews.llvm.org/D129023 --- flang/docs/ParserCombinators.md | 5 +- flang/lib/Parser/io-parsers.cpp | 128 +++++++++++++++++++++------------------- 2 files changed, 71 insertions(+), 62 deletions(-) diff --git a/flang/docs/ParserCombinators.md b/flang/docs/ParserCombinators.md index ff94d34..bb17509 100644 --- a/flang/docs/ParserCombinators.md +++ b/flang/docs/ParserCombinators.md @@ -155,7 +155,10 @@ is built. All of the following parsers consume characters acquired from * `"..."_tok` match the content of the string, skipping spaces before and after. Internal spaces are optional matches. The `_tok` suffix is optional when the parser appears before the combinator `>>` or after - the combinator `/`. + the combinator `/`. If the quoted string ends in a character that + could appear in an identifier, a missing space will be diagnosed in + free form source in pedantic mode if the next character could also + be part of an identifier -- add a trailing blank to avoid this. * `"..."_sptok` is a string match in which the spaces are required in free form source. * `"..."_id` is a string match for a complete identifier (not a prefix of diff --git a/flang/lib/Parser/io-parsers.cpp b/flang/lib/Parser/io-parsers.cpp index 2296d84..c7ef96e 100644 --- a/flang/lib/Parser/io-parsers.cpp +++ b/flang/lib/Parser/io-parsers.cpp @@ -569,6 +569,11 @@ constexpr auto digits{repeat}; constexpr auto noInt{construct>()}; constexpr auto mandatoryDigits{construct>("." >> width)}; +// The extra trailing spaces in the following quoted edit descriptor token +// parsers are intentional: they inhibit any spurious warnings about missing +// spaces in pedantic mode that would otherwise be emitted if the edit +// descriptor were followed by a character that could appear in an identifier. + // R1307 data-edit-desc -> // I w [. m] | B w [. m] | O w [. m] | Z w [. m] | F w . d | // E w . d [E e] | EN w . d [E e] | ES w . d [E e] | EX w . d [E e] | @@ -576,59 +581,60 @@ constexpr auto mandatoryDigits{construct>("." >> width)}; // DT [char-literal-constant] [( v-list )] // (part 1 of 2) TYPE_PARSER(construct( - "I" >> pure(format::IntrinsicTypeDataEditDesc::Kind::I) || - "B" >> pure(format::IntrinsicTypeDataEditDesc::Kind::B) || - "O" >> pure(format::IntrinsicTypeDataEditDesc::Kind::O) || - "Z" >> pure(format::IntrinsicTypeDataEditDesc::Kind::Z), + "I " >> pure(format::IntrinsicTypeDataEditDesc::Kind::I) || + "B " >> pure(format::IntrinsicTypeDataEditDesc::Kind::B) || + "O " >> pure(format::IntrinsicTypeDataEditDesc::Kind::O) || + "Z " >> pure(format::IntrinsicTypeDataEditDesc::Kind::Z), mandatoryWidth, maybe("." >> digits), noInt) || construct( - "F" >> pure(format::IntrinsicTypeDataEditDesc::Kind::F) || - "D" >> pure(format::IntrinsicTypeDataEditDesc::Kind::D), + "F " >> pure(format::IntrinsicTypeDataEditDesc::Kind::F) || + "D " >> pure(format::IntrinsicTypeDataEditDesc::Kind::D), mandatoryWidth, mandatoryDigits, noInt) || construct( - "E" >> ("N" >> pure(format::IntrinsicTypeDataEditDesc::Kind::EN) || - "S" >> pure(format::IntrinsicTypeDataEditDesc::Kind::ES) || - "X" >> pure(format::IntrinsicTypeDataEditDesc::Kind::EX) || - pure(format::IntrinsicTypeDataEditDesc::Kind::E)), - mandatoryWidth, mandatoryDigits, maybe("E" >> digits)) || + "E " >> ("N " >> pure(format::IntrinsicTypeDataEditDesc::Kind::EN) || + "S " >> pure(format::IntrinsicTypeDataEditDesc::Kind::ES) || + "X " >> pure(format::IntrinsicTypeDataEditDesc::Kind::EX) || + pure(format::IntrinsicTypeDataEditDesc::Kind::E)), + mandatoryWidth, mandatoryDigits, maybe("E " >> digits)) || construct( - "G" >> pure(format::IntrinsicTypeDataEditDesc::Kind::G), mandatoryWidth, - mandatoryDigits, maybe("E" >> digits)) || + "G " >> pure(format::IntrinsicTypeDataEditDesc::Kind::G), + mandatoryWidth, mandatoryDigits, maybe("E " >> digits)) || construct( - "G" >> pure(format::IntrinsicTypeDataEditDesc::Kind::G) || - "L" >> pure(format::IntrinsicTypeDataEditDesc::Kind::L), + "G " >> pure(format::IntrinsicTypeDataEditDesc::Kind::G) || + "L " >> pure(format::IntrinsicTypeDataEditDesc::Kind::L), mandatoryWidth, noInt, noInt) || construct( - "A" >> pure(format::IntrinsicTypeDataEditDesc::Kind::A), maybe(width), + "A " >> pure(format::IntrinsicTypeDataEditDesc::Kind::A), maybe(width), noInt, noInt) || // PGI/Intel extension: omitting width (and all else that follows) extension( "nonstandard usage: abbreviated edit descriptor"_port_en_US, construct( - "I" >> pure(format::IntrinsicTypeDataEditDesc::Kind::I) || - ("B"_tok / !letter /* don't occlude BN & BZ */) >> + "I " >> pure(format::IntrinsicTypeDataEditDesc::Kind::I) || + ("B "_tok / !letter /* don't occlude BN & BZ */) >> pure(format::IntrinsicTypeDataEditDesc::Kind::B) || - "O" >> pure(format::IntrinsicTypeDataEditDesc::Kind::O) || - "Z" >> pure(format::IntrinsicTypeDataEditDesc::Kind::Z) || - "F" >> pure(format::IntrinsicTypeDataEditDesc::Kind::F) || - ("D"_tok / !letter /* don't occlude DT, DC, & DP */) >> + "O " >> pure(format::IntrinsicTypeDataEditDesc::Kind::O) || + "Z " >> pure(format::IntrinsicTypeDataEditDesc::Kind::Z) || + "F " >> pure(format::IntrinsicTypeDataEditDesc::Kind::F) || + ("D "_tok / !letter /* don't occlude DT, DC, & DP */) >> pure(format::IntrinsicTypeDataEditDesc::Kind::D) || - "E" >> - ("N" >> pure(format::IntrinsicTypeDataEditDesc::Kind::EN) || - "S" >> + "E " >> + ("N " >> + pure(format::IntrinsicTypeDataEditDesc::Kind::EN) || + "S " >> pure(format::IntrinsicTypeDataEditDesc::Kind::ES) || - "X" >> + "X " >> pure(format::IntrinsicTypeDataEditDesc::Kind::EX) || pure(format::IntrinsicTypeDataEditDesc::Kind::E)) || - "G" >> pure(format::IntrinsicTypeDataEditDesc::Kind::G) || - "L" >> pure(format::IntrinsicTypeDataEditDesc::Kind::L), + "G " >> pure(format::IntrinsicTypeDataEditDesc::Kind::G) || + "L " >> pure(format::IntrinsicTypeDataEditDesc::Kind::L), noInt, noInt, noInt))) // R1307 data-edit-desc (part 2 of 2) // R1312 v -> [sign] digit-string constexpr SignedDigitStringIgnoreSpaces scaleFactor; TYPE_PARSER(construct( - "D" >> "T"_tok >> defaulted(charLiteralConstantWithoutKind), + "D T" >> defaulted(charLiteralConstantWithoutKind), defaulted(parenthesized(nonemptyList(scaleFactor))))) // R1314 k -> [sign] digit-string @@ -645,46 +651,46 @@ constexpr PositiveDigitStringIgnoreSpaces count; // R1319 round-edit-desc -> RU | RD | RZ | RN | RC | RP // R1320 decimal-edit-desc -> DC | DP TYPE_PARSER(construct( - "T" >> ("L" >> pure(format::ControlEditDesc::Kind::TL) || - "R" >> pure(format::ControlEditDesc::Kind::TR) || - pure(format::ControlEditDesc::Kind::T)), + "T L " >> pure(format::ControlEditDesc::Kind::TL) || + "T R " >> pure(format::ControlEditDesc::Kind::TR) || + "T " >> pure(format::ControlEditDesc::Kind::T), count) || construct(count, - "X" >> pure(format::ControlEditDesc::Kind::X) || + "X " >> pure(format::ControlEditDesc::Kind::X) || "/" >> pure(format::ControlEditDesc::Kind::Slash)) || construct( - "X" >> pure(format::ControlEditDesc::Kind::X) || + "X " >> pure(format::ControlEditDesc::Kind::X) || "/" >> pure(format::ControlEditDesc::Kind::Slash)) || construct( - scaleFactor, "P" >> pure(format::ControlEditDesc::Kind::P)) || + scaleFactor, "P " >> pure(format::ControlEditDesc::Kind::P)) || construct( ":" >> pure(format::ControlEditDesc::Kind::Colon)) || - "S" >> ("S" >> construct( - pure(format::ControlEditDesc::Kind::SS)) || - "P" >> construct( - pure(format::ControlEditDesc::Kind::SP)) || - construct( - pure(format::ControlEditDesc::Kind::S))) || - "B" >> ("N" >> construct( - pure(format::ControlEditDesc::Kind::BN)) || - "Z" >> construct( - pure(format::ControlEditDesc::Kind::BZ))) || - "R" >> ("U" >> construct( - pure(format::ControlEditDesc::Kind::RU)) || - "D" >> construct( - pure(format::ControlEditDesc::Kind::RD)) || - "Z" >> construct( - pure(format::ControlEditDesc::Kind::RZ)) || - "N" >> construct( - pure(format::ControlEditDesc::Kind::RN)) || - "C" >> construct( - pure(format::ControlEditDesc::Kind::RC)) || - "P" >> construct( - pure(format::ControlEditDesc::Kind::RP))) || - "D" >> ("C" >> construct( - pure(format::ControlEditDesc::Kind::DC)) || - "P" >> construct( - pure(format::ControlEditDesc::Kind::DP))) || + "S " >> ("S " >> construct( + pure(format::ControlEditDesc::Kind::SS)) || + "P " >> construct( + pure(format::ControlEditDesc::Kind::SP)) || + construct( + pure(format::ControlEditDesc::Kind::S))) || + "B " >> ("N " >> construct( + pure(format::ControlEditDesc::Kind::BN)) || + "Z " >> construct( + pure(format::ControlEditDesc::Kind::BZ))) || + "R " >> ("U " >> construct( + pure(format::ControlEditDesc::Kind::RU)) || + "D " >> construct( + pure(format::ControlEditDesc::Kind::RD)) || + "Z " >> construct( + pure(format::ControlEditDesc::Kind::RZ)) || + "N " >> construct( + pure(format::ControlEditDesc::Kind::RN)) || + "C " >> construct( + pure(format::ControlEditDesc::Kind::RC)) || + "P " >> construct( + pure(format::ControlEditDesc::Kind::RP))) || + "D " >> ("C " >> construct( + pure(format::ControlEditDesc::Kind::DC)) || + "P " >> construct( + pure(format::ControlEditDesc::Kind::DP))) || extension( "nonstandard usage: $ and \\ control edit descriptors"_port_en_US, "$" >> construct( -- 2.7.4