[flang] Define LanguageFeatureControl, use it everywhere.
authorpeter klausler <pklausler@nvidia.com>
Wed, 18 Jul 2018 18:19:21 +0000 (11:19 -0700)
committerpeter klausler <pklausler@nvidia.com>
Thu, 19 Jul 2018 16:54:24 +0000 (09:54 -0700)
Original-commit: flang-compiler/f18@9a95107610c0d785c8b56576909ea4cf6efd5814
Reviewed-on: https://github.com/flang-compiler/f18/pull/130
Tree-same-pre-rewrite: false

flang/lib/parser/basic-parsers.h
flang/lib/parser/features.h
flang/lib/parser/parse-state.h
flang/lib/parser/parsing.cc
flang/lib/parser/parsing.h
flang/lib/parser/prescan.cc
flang/lib/parser/prescan.h
flang/lib/parser/token-parsers.h
flang/lib/parser/user-state.h
flang/tools/f18/f18.cc

index c2b937f..6588be1 100644 (file)
@@ -1308,7 +1308,7 @@ public:
   constexpr NonstandardParser(const PA &parser) : parser_{parser} {}
   std::optional<resultType> Parse(ParseState &state) const {
     if (UserState * ustate{state.userState()}) {
-      if (!ustate->IsEnabled(LF)) {
+      if (!ustate->features().IsEnabled(LF)) {
         return {};
       }
     }
@@ -1340,7 +1340,7 @@ public:
   constexpr DeprecatedParser(const PA &parser) : parser_{parser} {}
   std::optional<resultType> Parse(ParseState &state) const {
     if (UserState * ustate{state.userState()}) {
-      if (!ustate->IsEnabled(LF)) {
+      if (!ustate->features().IsEnabled(LF)) {
         return {};
       }
     }
index 0ade901..ef8da55 100644 (file)
 
 namespace Fortran::parser {
 
-ENUM_CLASS(LanguageFeature, BackslashEscapes, LogicalAbbreviations, XOROperator,
-    PunctuationInNames, OptionalFreeFormSpace, BOZExtensions, EmptyStatement,
-    OldDebugLines, OpenMP, Extension, Deprecation)
+ENUM_CLASS(LanguageFeature, BackslashEscapes, OldDebugLines,
+    FixedFormContinuationWithColumn1Ampersand, LogicalAbbreviations,
+    XOROperator, PunctuationInNames, OptionalFreeFormSpace, BOZExtensions,
+    EmptyStatement, OpenMP, Extension, Deprecation)
 
 using LanguageFeatures = common::EnumSet<LanguageFeature, 32>;
 
+class LanguageFeatureControl {
+public:
+  LanguageFeatureControl() {
+    disable_.set(LanguageFeature::OldDebugLines);
+    // These features, if enabled, conflict with valid standard usage.
+    disable_.set(LanguageFeature::LogicalAbbreviations);
+    disable_.set(LanguageFeature::XOROperator);
+  }
+  LanguageFeatureControl(const LanguageFeatureControl &) = default;
+  void Enable(LanguageFeature f, bool yes = true) { disable_.set(f, !yes); }
+  void EnableWarning(LanguageFeature f, bool yes = true) { warn_.set(f, yes); }
+  void WarnOnAllNonstandard(bool yes = true) { warnAll_ = yes; }
+  bool IsEnabled(LanguageFeature f) const { return !disable_.test(f); }
+  bool ShouldWarn(LanguageFeature f) const {
+    return (warnAll_ && f != LanguageFeature::OpenMP) || warn_.test(f);
+  }
+
+private:
+  LanguageFeatures disable_;
+  LanguageFeatures warn_;
+  bool warnAll_{false};
+};
+
 }  // namespace Fortran::parser
 #endif  // FORTRAN_PARSER_FEATURES_H_
index 83f6da3..e78ca76 100644 (file)
@@ -179,10 +179,17 @@ public:
   void Nonstandard(
       CharBlock range, LanguageFeature lf, const MessageFixedText &msg) {
     anyConformanceViolation_ = true;
-    if (userState_ != nullptr && userState_->Warn(lf)) {
+    if (userState_ != nullptr && userState_->features().ShouldWarn(lf)) {
       Say(range, msg);
     }
   }
+  bool IsNonstandardOk(LanguageFeature lf, const MessageFixedText &msg) {
+    if (userState_ != nullptr && !userState_->features().IsEnabled(lf)) {
+      return false;
+    }
+    Nonstandard(lf, msg);
+    return true;
+  }
 
   bool IsAtEnd() const { return p_ >= limit_; }
 
index aed818f..07887e6 100644 (file)
@@ -63,17 +63,12 @@ void Parsing::Prescan(const std::string &path, Options options) {
       preprocessor.Undefine(predef.first);
     }
   }
-  Prescanner prescanner{messages_, cooked_, preprocessor};
+  Prescanner prescanner{messages_, cooked_, preprocessor, options.features};
   prescanner.set_fixedForm(options.isFixedForm)
       .set_fixedFormColumnLimit(options.fixedFormColumns)
       .set_encoding(options.encoding)
-      .set_enableBackslashEscapesInCharLiterals(  // TODO pmk
-          options.enabled.test(LanguageFeature::BackslashEscapes))
-      .set_enableOldDebugLines(
-          options.enabled.test(LanguageFeature::OldDebugLines))
-      .set_warnOnNonstandardUsage(options_.isStrictlyStandard)
       .AddCompilerDirectiveSentinel("dir$");
-  if (options.enabled.test(LanguageFeature::OpenMP)) {
+  if (options.features.IsEnabled(LanguageFeature::OpenMP)) {
     prescanner.AddCompilerDirectiveSentinel("$omp");
   }
   ProvenanceRange range{
@@ -83,7 +78,7 @@ void Parsing::Prescan(const std::string &path, Options options) {
 }
 
 void Parsing::DumpCookedChars(std::ostream &out) const {
-  UserState userState{cooked_};
+  UserState userState{cooked_, LanguageFeatureControl{}};
   ParseState parseState{cooked_};
   parseState.set_inFixedForm(options_.isFixedForm).set_userState(&userState);
   while (std::optional<const char *> p{parseState.GetNextChar()}) {
@@ -98,12 +93,10 @@ void Parsing::DumpParsingLog(std::ostream &out) const {
 }
 
 void Parsing::Parse(std::ostream *out) {
-  UserState userState{cooked_};
+  UserState userState{cooked_, options_.features};
   userState.set_debugOutput(out)
       .set_instrumentedParse(options_.instrumentedParse)
       .set_log(&log_);
-  userState.Enable(options_.enabled);
-  userState.EnableWarnings(options_.warning);
   ParseState parseState{cooked_};
   parseState.set_inFixedForm(options_.isFixedForm)
       .set_encoding(options_.encoding)
index 9d5dff7..5c6cf18 100644 (file)
@@ -37,7 +37,7 @@ struct Options {
   bool isFixedForm{false};
   int fixedFormColumns{72};
   bool isStrictlyStandard{false};
-  LanguageFeatures enabled, warning;
+  LanguageFeatureControl features;
   Encoding encoding{Encoding::UTF8};
   std::vector<std::string> searchDirectories;
   std::vector<Predefinition> predefinitions;
index 3d186b0..ccd7754 100644 (file)
@@ -29,19 +29,17 @@ namespace Fortran::parser {
 
 static constexpr int maxPrescannerNesting{100};
 
-Prescanner::Prescanner(
-    Messages &messages, CookedSource &cooked, Preprocessor &preprocessor)
-  : messages_{messages}, cooked_{cooked}, preprocessor_{preprocessor} {}
+Prescanner::Prescanner(Messages &messages, CookedSource &cooked,
+    Preprocessor &preprocessor, LanguageFeatureControl lfc)
+  : messages_{messages}, cooked_{cooked},
+    preprocessor_{preprocessor}, features_{lfc} {}
 
 Prescanner::Prescanner(const Prescanner &that)
   : messages_{that.messages_}, cooked_{that.cooked_},
-    preprocessor_{that.preprocessor_}, inFixedForm_{that.inFixedForm_},
+    preprocessor_{that.preprocessor_}, features_{that.features_},
+    inFixedForm_{that.inFixedForm_},
     fixedFormColumnLimit_{that.fixedFormColumnLimit_},
-    encoding_{that.encoding_}, enableOldDebugLines_{that.enableOldDebugLines_},
-    enableBackslashEscapesInCharLiterals_{
-        that.enableBackslashEscapesInCharLiterals_},
-    warnOnNonstandardUsage_{that.warnOnNonstandardUsage_},
-    prescannerNesting_{that.prescannerNesting_ + 1},
+    encoding_{that.encoding_}, prescannerNesting_{that.prescannerNesting_ + 1},
     compilerDirectiveBloomFilter_{that.compilerDirectiveBloomFilter_},
     compilerDirectiveSentinels_{that.compilerDirectiveSentinels_} {}
 
@@ -451,11 +449,11 @@ void Prescanner::QuotedCharacterLiteral(TokenSequence &tokens) {
   const auto emit{[&](char ch) { EmitChar(tokens, ch); }};
   const auto insert{[&](char ch) { EmitInsertedChar(tokens, ch); }};
   bool escape{false};
+  bool escapesEnabled{features_.IsEnabled(LanguageFeature::BackslashEscapes)};
   while (true) {
     char ch{*at_};
-    escape = !escape && ch == '\\' && enableBackslashEscapesInCharLiterals_;
-    EmitQuotedChar(
-        ch, emit, insert, false, !enableBackslashEscapesInCharLiterals_);
+    escape = !escape && ch == '\\' && escapesEnabled;
+    EmitQuotedChar(ch, emit, insert, false, !escapesEnabled);
     while (PadOutCharacterLiteral(tokens)) {
     }
     if (*at_ == '\n') {
@@ -548,7 +546,8 @@ bool Prescanner::IsFixedFormCommentLine(const char *start) const {
   char ch{*p};
   if (ch == '*' || ch == 'C' || ch == 'c' ||
       ch == '%' ||  // VAX %list, %eject, &c.
-      ((ch == 'D' || ch == 'd') && !enableOldDebugLines_)) {
+      ((ch == 'D' || ch == 'd') &&
+          !features_.IsEnabled(LanguageFeature::OldDebugLines))) {
     return true;
   }
   bool anyTabs{false};
@@ -733,9 +732,12 @@ const char *Prescanner::FixedFormContinuationLine(bool mightNeedSpace) {
     return nullptr;
   } else {
     // Normal case: not in a compiler directive.
-    if (col1 == '&') {
+    if (col1 == '&' &&
+        features_.IsEnabled(
+            LanguageFeature::FixedFormContinuationWithColumn1Ampersand)) {
       // Extension: '&' as continuation marker
-      if (warnOnNonstandardUsage_) {
+      if (features_.ShouldWarn(
+              LanguageFeature::FixedFormContinuationWithColumn1Ampersand)) {
         Say("nonstandard usage"_en_US, GetProvenance(lineStart_));
       }
       return lineStart_ + 1;
index d886bd6..eaf7aae 100644 (file)
@@ -23,6 +23,7 @@
 // inclusion, and driving the Fortran source preprocessor.
 
 #include "characters.h"
+#include "features.h"
 #include "message.h"
 #include "provenance.h"
 #include "token-sequence.h"
@@ -38,7 +39,8 @@ class Preprocessor;
 
 class Prescanner {
 public:
-  Prescanner(Messages &, CookedSource &, Preprocessor &);
+  Prescanner(
+      Messages &, CookedSource &, Preprocessor &, LanguageFeatureControl);
   Prescanner(const Prescanner &);
 
   Messages &messages() const { return messages_; }
@@ -51,22 +53,10 @@ public:
     encoding_ = code;
     return *this;
   }
-  Prescanner &set_enableOldDebugLines(bool yes) {
-    enableOldDebugLines_ = yes;
-    return *this;
-  }
-  Prescanner &set_enableBackslashEscapesInCharLiterals(bool yes) {
-    enableBackslashEscapesInCharLiterals_ = yes;
-    return *this;
-  }
   Prescanner &set_fixedFormColumnLimit(int limit) {
     fixedFormColumnLimit_ = limit;
     return *this;
   }
-  Prescanner &set_warnOnNonstandardUsage(bool yes) {
-    warnOnNonstandardUsage_ = yes;
-    return *this;
-  }
 
   Prescanner &AddCompilerDirectiveSentinel(const std::string &);
 
@@ -176,12 +166,10 @@ private:
   Messages &messages_;
   CookedSource &cooked_;
   Preprocessor &preprocessor_;
+  LanguageFeatureControl features_;
   bool inFixedForm_{false};
   int fixedFormColumnLimit_{72};
   Encoding encoding_{Encoding::UTF8};
-  bool enableOldDebugLines_{false};
-  bool enableBackslashEscapesInCharLiterals_{false};
-  bool warnOnNonstandardUsage_{false};
   int delimiterNesting_{0};
   int prescannerNesting_{0};
 
index 9731e83..16235a5 100644 (file)
@@ -296,17 +296,6 @@ template<char quote> struct CharLiteral {
   }
 };
 
-static bool IsNonstandardBOZOk(ParseState &state) {
-  if (UserState * ustate{state.userState()}) {
-    if (!ustate->IsEnabled(LanguageFeature::BOZExtensions)) {
-      return false;
-    }
-  }
-  state.Nonstandard(
-      LanguageFeature::BOZExtensions, "nonstandard BOZ literal"_en_US);
-  return true;
-}
-
 // Parse "BOZ" binary literal quoted constants.
 // As extensions, support X as an alternate hexadecimal marker, and allow
 // BOZX markers to appear as suffixes.
@@ -330,7 +319,9 @@ struct BOZLiteral {
     if (!at.has_value()) {
       return {};
     }
-    if (**at == 'x' && !IsNonstandardBOZOk(state)) {
+    if (**at == 'x' &&
+        !state.IsNonstandardOk(
+            LanguageFeature::BOZExtensions, "nonstandard BOZ literal"_en_US)) {
       return {};
     }
     if (baseChar(**at)) {
@@ -365,8 +356,9 @@ struct BOZLiteral {
 
     if (!shift.has_value()) {
       // extension: base allowed to appear as suffix, too
-      if (!IsNonstandardBOZOk(state) ||
-          !(at = nextCh.Parse(state)).has_value() || !baseChar(**at)) {
+      if (!(at = nextCh.Parse(state)).has_value() || !baseChar(**at) ||
+          !state.IsNonstandardOk(LanguageFeature::BOZExtensions,
+              "nonstandard BOZ literal"_en_US)) {
         return {};
       }
       spaceCheck.Parse(state);
@@ -700,9 +692,9 @@ constexpr struct SkipStuffBeforeStatement {
         } else {
           break;
         }
-      } else if (**at == ';') {
-        state.Nonstandard(
-            LanguageFeature::EmptyStatement, "empty statement"_en_US);
+      } else if (**at == ';' &&
+          state.IsNonstandardOk(
+              LanguageFeature::EmptyStatement, "empty statement"_en_US)) {
         state.UncheckedAdvance();
       } else {
         break;
index 9844f77..84cb9da 100644 (file)
@@ -40,9 +40,11 @@ class Success {};  // for when one must return something that's present
 
 class UserState {
 public:
-  explicit UserState(const CookedSource &cooked) : cooked_{cooked} {}
+  UserState(const CookedSource &cooked, LanguageFeatureControl features)
+    : cooked_{cooked}, features_{features} {}
 
   const CookedSource &cooked() const { return cooked_; }
+  const LanguageFeatureControl &features() const { return features_; }
 
   std::ostream *debugOutput() const { return debugOutput_; }
   UserState &set_debugOutput(std::ostream *out) {
@@ -91,41 +93,6 @@ public:
     return oldStructureComponents_.find(name) != oldStructureComponents_.end();
   }
 
-  UserState &Enable(LanguageFeature f) {
-    enabled_.set(f);
-    return *this;
-  }
-  UserState &Enable(LanguageFeatures fs) {
-    enabled_ |= fs;
-    return *this;
-  }
-  UserState &Disable(LanguageFeature f) {
-    enabled_.reset(f);
-    return *this;
-  }
-  UserState &Disable(LanguageFeatures fs) {
-    enabled_ &= ~fs;
-    return *this;
-  }
-  bool IsEnabled(LanguageFeature f) { return enabled_.test(f); }
-  UserState &EnableWarning(LanguageFeature f) {
-    warning_.set(f);
-    return *this;
-  }
-  UserState &EnableWarnings(LanguageFeatures fs) {
-    warning_ |= fs;
-    return *this;
-  }
-  UserState &DisableWarning(LanguageFeature f) {
-    warning_.reset(f);
-    return *this;
-  }
-  UserState &DisableWarnings(LanguageFeatures fs) {
-    warning_ &= ~fs;
-    return *this;
-  }
-  bool Warn(LanguageFeature f) { return warning_.test(f); }
-
 private:
   const CookedSource &cooked_;
 
@@ -139,7 +106,7 @@ private:
 
   std::set<CharBlock> oldStructureComponents_;
 
-  LanguageFeatures enabled_, warning_;
+  LanguageFeatureControl features_;
 };
 
 // Definitions of parser classes that manipulate the UserState.
index 798ef77..2666dd3 100644 (file)
@@ -300,13 +300,6 @@ int main(int argc, char *const argv[]) {
   options.predefinitions.emplace_back("__F18_MINOR__", "1");
   options.predefinitions.emplace_back("__F18_PATCHLEVEL__", "1");
 
-  options.enabled.set(Fortran::parser::LanguageFeature::PunctuationInNames);
-  options.enabled.set(Fortran::parser::LanguageFeature::OptionalFreeFormSpace);
-  options.enabled.set(Fortran::parser::LanguageFeature::BOZExtensions);
-  options.enabled.set(Fortran::parser::LanguageFeature::EmptyStatement);
-  options.enabled.set(Fortran::parser::LanguageFeature::Extension);  // pmk
-  options.enabled.set(Fortran::parser::LanguageFeature::Deprecation);
-
   std::vector<std::string> fortranSources, otherSources, relocatables;
   bool anyFiles{false};
 
@@ -350,23 +343,27 @@ int main(int argc, char *const argv[]) {
     } else if (arg == "-Mextend") {
       options.fixedFormColumns = 132;
     } else if (arg == "-Mbackslash") {
-      options.enabled.reset(Fortran::parser::LanguageFeature::BackslashEscapes);
+      options.features.Enable(
+          Fortran::parser::LanguageFeature::BackslashEscapes, false);
     } else if (arg == "-Mnobackslash") {
-      options.enabled.set(Fortran::parser::LanguageFeature::BackslashEscapes);
+      options.features.Enable(
+          Fortran::parser::LanguageFeature::BackslashEscapes);
     } else if (arg == "-Mstandard") {
-      options.isStrictlyStandard = true;
+      options.features.WarnOnAllNonstandard();
     } else if (arg == "-fopenmp") {
-      options.enabled.set(Fortran::parser::LanguageFeature::OpenMP);
+      options.features.Enable(Fortran::parser::LanguageFeature::OpenMP);
     } else if (arg == "-Werror") {
       driver.warningsAreErrors = true;
     } else if (arg == "-ed") {
-      options.enabled.set(Fortran::parser::LanguageFeature::OldDebugLines);
+      options.features.Enable(Fortran::parser::LanguageFeature::OldDebugLines);
     } else if (arg == "-E") {
       driver.dumpCookedChars = true;
     } else if (arg == "-fbackslash") {
-      options.enabled.set(Fortran::parser::LanguageFeature::BackslashEscapes);
+      options.features.Enable(
+          Fortran::parser::LanguageFeature::BackslashEscapes);
     } else if (arg == "-fno-backslash") {
-      options.enabled.reset(Fortran::parser::LanguageFeature::BackslashEscapes);
+      options.features.Enable(
+          Fortran::parser::LanguageFeature::BackslashEscapes, false);
     } else if (arg == "-fdebug-dump-provenance") {
       driver.dumpProvenance = true;
     } else if (arg == "-fdebug-dump-parse-tree") {
@@ -448,8 +445,7 @@ int main(int argc, char *const argv[]) {
   driver.encoding = options.encoding;
 
   if (options.isStrictlyStandard) {
-    options.warning |= options.enabled;
-    options.warning.reset(Fortran::parser::LanguageFeature::OpenMP);
+    options.features.WarnOnAllNonstandard();
   }
 
   if (!anyFiles) {