[flang-commits] [flang] [flang] Ensure that portability warnings are conditional (PR #71857)

via flang-commits flang-commits at lists.llvm.org
Thu Nov 9 11:47:34 PST 2023


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-parser
@llvm/pr-subscribers-flang-openmp
@llvm/pr-subscribers-openacc

@llvm/pr-subscribers-flang-driver

Author: Peter Klausler (klausler)

<details>
<summary>Changes</summary>

Before emitting a warning message, code should check that the usage in question should be diagnosed by calling ShouldWarn().  A fair number of sites in the code do not, and can emit portability warnings unconditionally, which can confuse a user that hasn't asked for them (-pedantic) and isn't terribly concerned about portability *to* other compilers.

Add calls to ShouldWarn() or IsEnabled() around messages that need them, and add -pedantic to tests that now require it to test their portability messages, and add more expected message lines to those tests when -pedantic causes other diagnostics to fire.

---

Patch is 104.67 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/71857.diff


78 Files Affected:

- (modified) flang/include/flang/Common/Fortran-features.h (+11-2) 
- (modified) flang/include/flang/Evaluate/common.h (+16-6) 
- (modified) flang/include/flang/Lower/Bridge.h (+10-3) 
- (modified) flang/lib/Evaluate/check-expression.cpp (+54-19) 
- (modified) flang/lib/Evaluate/intrinsics.cpp (+40-28) 
- (modified) flang/lib/Frontend/FrontendActions.cpp (+2-1) 
- (modified) flang/lib/Lower/Bridge.cpp (+6-3) 
- (modified) flang/lib/Parser/expr-parsers.cpp (+2-4) 
- (modified) flang/lib/Parser/prescan.cpp (+19-9) 
- (modified) flang/lib/Semantics/check-allocate.cpp (+5-3) 
- (modified) flang/lib/Semantics/check-call.cpp (+61-35) 
- (modified) flang/lib/Semantics/check-data.cpp (+22-6) 
- (modified) flang/lib/Semantics/check-declarations.cpp (+111-76) 
- (modified) flang/lib/Semantics/check-directive-structure.h (+23-14) 
- (modified) flang/lib/Semantics/check-do-forall.cpp (+5-3) 
- (modified) flang/lib/Semantics/check-omp-structure.cpp (+13-10) 
- (modified) flang/lib/Semantics/compute-offsets.cpp (+5-3) 
- (modified) flang/lib/Semantics/data-to-inits.cpp (+9-4) 
- (modified) flang/lib/Semantics/expression.cpp (+29-15) 
- (modified) flang/lib/Semantics/pointer-assignment.cpp (+1-1) 
- (modified) flang/lib/Semantics/resolve-names.cpp (+38-23) 
- (modified) flang/lib/Semantics/semantics.cpp (+3-2) 
- (modified) flang/test/Evaluate/folding04.f90 (+3-3) 
- (modified) flang/test/Evaluate/folding06.f90 (+4-4) 
- (modified) flang/test/Parser/badlabel.f (+1-1) 
- (modified) flang/test/Parser/continuation-before-quote.f90 (+1-1) 
- (modified) flang/test/Parser/excessive-continuations.f90 (+1-1) 
- (modified) flang/test/Semantics/OpenACC/acc-branch.f90 (+3-3) 
- (modified) flang/test/Semantics/OpenACC/acc-data.f90 (+1-1) 
- (modified) flang/test/Semantics/OpenACC/acc-serial.f90 (+1-1) 
- (modified) flang/test/Semantics/OpenMP/copying.f90 (+1-1) 
- (modified) flang/test/Semantics/OpenMP/declare-target03.f90 (+1-1) 
- (modified) flang/test/Semantics/OpenMP/nested-target.f90 (+1-1) 
- (modified) flang/test/Semantics/OpenMP/threadprivate03.f90 (+1-1) 
- (modified) flang/test/Semantics/allocate09.f90 (+1-1) 
- (modified) flang/test/Semantics/associated.f90 (+9-8) 
- (modified) flang/test/Semantics/bind-c02.f90 (+1-1) 
- (modified) flang/test/Semantics/bind-c06.f90 (+1-1) 
- (modified) flang/test/Semantics/bind-c11.f90 (+1-1) 
- (modified) flang/test/Semantics/bindings01.f90 (+1-1) 
- (modified) flang/test/Semantics/block-data01.f90 (+1-1) 
- (modified) flang/test/Semantics/c_loc01.f90 (+1-1) 
- (modified) flang/test/Semantics/call01.f90 (+3-3) 
- (modified) flang/test/Semantics/call02.f90 (+1-1) 
- (modified) flang/test/Semantics/call09.f90 (+1-1) 
- (modified) flang/test/Semantics/call31.f90 (+1-1) 
- (modified) flang/test/Semantics/common-blocks-warn.f90 (+1-1) 
- (modified) flang/test/Semantics/common-blocks.f90 (+1-1) 
- (modified) flang/test/Semantics/data06.f90 (+1-1) 
- (modified) flang/test/Semantics/data08.f90 (+1-1) 
- (modified) flang/test/Semantics/data11.f90 (+1-1) 
- (modified) flang/test/Semantics/data14.f90 (+1-1) 
- (modified) flang/test/Semantics/declarations04.f90 (+1-1) 
- (modified) flang/test/Semantics/dim01.f90 (+1-1) 
- (modified) flang/test/Semantics/expr-errors05.f90 (+3-1) 
- (modified) flang/test/Semantics/generic06.f90 (+1-1) 
- (modified) flang/test/Semantics/ignore_tkr01.f90 (+1-1) 
- (modified) flang/test/Semantics/io11.f90 (+1-2) 
- (modified) flang/test/Semantics/long-name.f90 (+1-1) 
- (modified) flang/test/Semantics/modfile43.f90 (+1-1) 
- (modified) flang/test/Semantics/modfile54.f90 (+1-1) 
- (modified) flang/test/Semantics/pointer01.f90 (+1-1) 
- (modified) flang/test/Semantics/procinterface02.f90 (+1-1) 
- (modified) flang/test/Semantics/procinterface04.f90 (+1-1) 
- (modified) flang/test/Semantics/resolve05.f90 (+1-1) 
- (modified) flang/test/Semantics/resolve106.f90 (+1-1) 
- (modified) flang/test/Semantics/resolve114.f90 (+1-1) 
- (modified) flang/test/Semantics/resolve118.f90 (+1-1) 
- (modified) flang/test/Semantics/resolve20.f90 (+1-1) 
- (modified) flang/test/Semantics/resolve46.f90 (+1-1) 
- (modified) flang/test/Semantics/resolve59.f90 (+1-1) 
- (modified) flang/test/Semantics/resolve85.f90 (+2-2) 
- (modified) flang/test/Semantics/stmt-func01.f90 (+1-1) 
- (modified) flang/test/Semantics/stmt-func02.f90 (+1-1) 
- (modified) flang/tools/bbc/bbc.cpp (+1-1) 
- (modified) flang/unittests/Evaluate/expression.cpp (+2-1) 
- (modified) flang/unittests/Evaluate/folding.cpp (+5-4) 
- (modified) flang/unittests/Evaluate/intrinsics.cpp (+3-1) 


``````````diff
diff --git a/flang/include/flang/Common/Fortran-features.h b/flang/include/flang/Common/Fortran-features.h
index 94a39c50e049b11..7e518a210f01cd3 100644
--- a/flang/include/flang/Common/Fortran-features.h
+++ b/flang/include/flang/Common/Fortran-features.h
@@ -37,14 +37,23 @@ ENUM_CLASS(LanguageFeature, BackslashEscapes, OldDebugLines,
     DistinguishableSpecifics, DefaultSave, PointerInSeqType, NonCharacterFormat,
     SaveMainProgram, SaveBigMainProgramVariables,
     DistinctArrayConstructorLengths, PPCVector, RelaxedIntentInChecking,
-    ForwardRefImplicitNoneData, NullActualForAllocatable)
+    ForwardRefImplicitNoneData, NullActualForAllocatable,
+    ActualIntegerConvertedToSmallerKind, HollerithOrCharacterAsBOZ,
+    BindingAsProcedure, StatementFunctionExtensions,
+    UseGenericIntrinsicWhenSpecificDoesntMatch, DataStmtExtensions,
+    RedundantContiguous, InitBlankCommon, EmptyBindCDerivedType,
+    MiscSourceExtensions, AllocateToOtherLength, LongNames, IntrinsicAsSpecific,
+    BenignNameClash, BenignRedundancy, NullMoldAllocatableComponentValue,
+    NopassScalarBase, MiscUseExtensions, ImpliedDoIndexScope,
+    DistinctCommonSizes)
 
 // Portability and suspicious usage warnings for conforming code
 ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable,
     NonTargetPassedToTarget, PointerToPossibleNoncontiguous,
     ShortCharacterActual, ExprPassedToVolatile, ImplicitInterfaceActual,
     PolymorphicTransferArg, PointerComponentTransferArg, TransferSizePresence,
-    F202XAllocatableBreakingChange)
+    F202XAllocatableBreakingChange, DimMustBePresent, CommonBlockPadding,
+    LogicalVsCBool, BindCCharLength)
 
 using LanguageFeatures = EnumSet<LanguageFeature, LanguageFeature_enumSize>;
 using UsageWarnings = EnumSet<UsageWarning, UsageWarning_enumSize>;
diff --git a/flang/include/flang/Evaluate/common.h b/flang/include/flang/Evaluate/common.h
index d05072742a48ca8..c8d93e0849229f5 100644
--- a/flang/include/flang/Evaluate/common.h
+++ b/flang/include/flang/Evaluate/common.h
@@ -9,6 +9,7 @@
 #ifndef FORTRAN_EVALUATE_COMMON_H_
 #define FORTRAN_EVALUATE_COMMON_H_
 
+#include "flang/Common/Fortran-features.h"
 #include "flang/Common/Fortran.h"
 #include "flang/Common/default-kinds.h"
 #include "flang/Common/enum-set.h"
@@ -215,22 +216,27 @@ template <typename A> class Expr;
 class FoldingContext {
 public:
   FoldingContext(const common::IntrinsicTypeDefaultKinds &d,
-      const IntrinsicProcTable &t, const TargetCharacteristics &c)
-      : defaults_{d}, intrinsics_{t}, targetCharacteristics_{c} {}
+      const IntrinsicProcTable &t, const TargetCharacteristics &c,
+      const common::LanguageFeatureControl &lfc)
+      : defaults_{d}, intrinsics_{t}, targetCharacteristics_{c},
+        languageFeatures_{lfc} {}
   FoldingContext(const parser::ContextualMessages &m,
       const common::IntrinsicTypeDefaultKinds &d, const IntrinsicProcTable &t,
-      const TargetCharacteristics &c)
-      : messages_{m}, defaults_{d}, intrinsics_{t}, targetCharacteristics_{c} {}
+      const TargetCharacteristics &c, const common::LanguageFeatureControl &lfc)
+      : messages_{m}, defaults_{d}, intrinsics_{t}, targetCharacteristics_{c},
+        languageFeatures_{lfc} {}
   FoldingContext(const FoldingContext &that)
       : messages_{that.messages_}, defaults_{that.defaults_},
         intrinsics_{that.intrinsics_},
         targetCharacteristics_{that.targetCharacteristics_},
-        pdtInstance_{that.pdtInstance_}, impliedDos_{that.impliedDos_} {}
+        pdtInstance_{that.pdtInstance_}, impliedDos_{that.impliedDos_},
+        languageFeatures_{that.languageFeatures_} {}
   FoldingContext(
       const FoldingContext &that, const parser::ContextualMessages &m)
       : messages_{m}, defaults_{that.defaults_}, intrinsics_{that.intrinsics_},
         targetCharacteristics_{that.targetCharacteristics_},
-        pdtInstance_{that.pdtInstance_}, impliedDos_{that.impliedDos_} {}
+        pdtInstance_{that.pdtInstance_}, impliedDos_{that.impliedDos_},
+        languageFeatures_{that.languageFeatures_} {}
 
   parser::ContextualMessages &messages() { return messages_; }
   const parser::ContextualMessages &messages() const { return messages_; }
@@ -242,6 +248,9 @@ class FoldingContext {
   const TargetCharacteristics &targetCharacteristics() const {
     return targetCharacteristics_;
   }
+  const common::LanguageFeatureControl &languageFeatures() const {
+    return languageFeatures_;
+  }
   bool inModuleFile() const { return inModuleFile_; }
   FoldingContext &set_inModuleFile(bool yes = true) {
     inModuleFile_ = yes;
@@ -272,6 +281,7 @@ class FoldingContext {
   const semantics::DerivedTypeSpec *pdtInstance_{nullptr};
   bool inModuleFile_{false};
   std::map<parser::CharBlock, ConstantSubscript> impliedDos_;
+  const common::LanguageFeatureControl &languageFeatures_;
 };
 
 void RealFlagWarnings(FoldingContext &, const RealFlags &, const char *op);
diff --git a/flang/include/flang/Lower/Bridge.h b/flang/include/flang/Lower/Bridge.h
index b4ee77a0b166ec9..ecf82ba5bc3bb40 100644
--- a/flang/include/flang/Lower/Bridge.h
+++ b/flang/include/flang/Lower/Bridge.h
@@ -58,10 +58,11 @@ class LoweringBridge {
          const Fortran::parser::AllCookedSources &allCooked,
          llvm::StringRef triple, fir::KindMapping &kindMap,
          const Fortran::lower::LoweringOptions &loweringOptions,
-         const std::vector<Fortran::lower::EnvironmentDefault> &envDefaults) {
+         const std::vector<Fortran::lower::EnvironmentDefault> &envDefaults,
+         const Fortran::common::LanguageFeatureControl &languageFeatures) {
     return LoweringBridge(ctx, semanticsContext, defaultKinds, intrinsics,
                           targetCharacteristics, allCooked, triple, kindMap,
-                          loweringOptions, envDefaults);
+                          loweringOptions, envDefaults, languageFeatures);
   }
 
   //===--------------------------------------------------------------------===//
@@ -99,6 +100,10 @@ class LoweringBridge {
     return envDefaults;
   }
 
+  const Fortran::common::LanguageFeatureControl &getLanguageFeatures() const {
+    return languageFeatures;
+  }
+
   /// Create a folding context. Careful: this is very expensive.
   Fortran::evaluate::FoldingContext createFoldingContext() const;
 
@@ -132,7 +137,8 @@ class LoweringBridge {
       const Fortran::parser::AllCookedSources &cooked, llvm::StringRef triple,
       fir::KindMapping &kindMap,
       const Fortran::lower::LoweringOptions &loweringOptions,
-      const std::vector<Fortran::lower::EnvironmentDefault> &envDefaults);
+      const std::vector<Fortran::lower::EnvironmentDefault> &envDefaults,
+      const Fortran::common::LanguageFeatureControl &languageFeatures);
   LoweringBridge() = delete;
   LoweringBridge(const LoweringBridge &) = delete;
 
@@ -147,6 +153,7 @@ class LoweringBridge {
   fir::KindMapping &kindMap;
   const Fortran::lower::LoweringOptions &loweringOptions;
   const std::vector<Fortran::lower::EnvironmentDefault> &envDefaults;
+  const Fortran::common::LanguageFeatureControl &languageFeatures;
 };
 
 } // namespace lower
diff --git a/flang/lib/Evaluate/check-expression.cpp b/flang/lib/Evaluate/check-expression.cpp
index 531fc5ccc56c858..2f46ed7dccb6455 100644
--- a/flang/lib/Evaluate/check-expression.cpp
+++ b/flang/lib/Evaluate/check-expression.cpp
@@ -12,6 +12,7 @@
 #include "flang/Evaluate/tools.h"
 #include "flang/Evaluate/traverse.h"
 #include "flang/Evaluate/type.h"
+#include "flang/Semantics/semantics.h"
 #include "flang/Semantics/symbol.h"
 #include "flang/Semantics/tools.h"
 #include <set>
@@ -1030,23 +1031,46 @@ class StmtFunctionChecker
   using Result = std::optional<parser::Message>;
   using Base = AnyTraverse<StmtFunctionChecker, Result>;
   StmtFunctionChecker(const Symbol &sf, FoldingContext &context)
-      : Base{*this}, sf_{sf}, context_{context} {}
+      : Base{*this}, sf_{sf}, context_{context} {
+    if (!context_.languageFeatures().IsEnabled(
+            common::LanguageFeature::StatementFunctionExtensions)) {
+      severity_ = parser::Severity::Error;
+    } else if (context_.languageFeatures().ShouldWarn(
+                   common::LanguageFeature::StatementFunctionExtensions)) {
+      severity_ = parser::Severity::Portability;
+    }
+  }
   using Base::operator();
 
   template <typename T> Result operator()(const ArrayConstructor<T> &) const {
-    return parser::Message{sf_.name(),
-        "Statement function '%s' should not contain an array constructor"_port_en_US,
-        sf_.name()};
+    if (severity_) {
+      auto msg{
+          "Statement function '%s' should not contain an array constructor"_port_en_US};
+      msg.set_severity(*severity_);
+      return parser::Message{sf_.name(), std::move(msg), sf_.name()};
+    } else {
+      return std::nullopt;
+    }
   }
   Result operator()(const StructureConstructor &) const {
-    return parser::Message{sf_.name(),
-        "Statement function '%s' should not contain a structure constructor"_port_en_US,
-        sf_.name()};
+    if (severity_) {
+      auto msg{
+          "Statement function '%s' should not contain a structure constructor"_port_en_US};
+      msg.set_severity(*severity_);
+      return parser::Message{sf_.name(), std::move(msg), sf_.name()};
+    } else {
+      return std::nullopt;
+    }
   }
   Result operator()(const TypeParamInquiry &) const {
-    return parser::Message{sf_.name(),
-        "Statement function '%s' should not contain a type parameter inquiry"_port_en_US,
-        sf_.name()};
+    if (severity_) {
+      auto msg{
+          "Statement function '%s' should not contain a type parameter inquiry"_port_en_US};
+      msg.set_severity(*severity_);
+      return parser::Message{sf_.name(), std::move(msg), sf_.name()};
+    } else {
+      return std::nullopt;
+    }
   }
   Result operator()(const ProcedureDesignator &proc) const {
     if (const Symbol * symbol{proc.GetSymbol()}) {
@@ -1064,16 +1088,23 @@ class StmtFunctionChecker
       if (auto chars{
               characteristics::Procedure::Characterize(proc, context_)}) {
         if (!chars->CanBeCalledViaImplicitInterface()) {
-          return parser::Message(sf_.name(),
-              "Statement function '%s' should not reference function '%s' that requires an explicit interface"_port_en_US,
-              sf_.name(), symbol->name());
+          if (severity_) {
+            auto msg{
+                "Statement function '%s' should not reference function '%s' that requires an explicit interface"_port_en_US};
+            msg.set_severity(*severity_);
+            return parser::Message{
+                sf_.name(), std::move(msg), sf_.name(), symbol->name()};
+          }
         }
       }
     }
     if (proc.Rank() > 0) {
-      return parser::Message(sf_.name(),
-          "Statement function '%s' should not reference a function that returns an array"_port_en_US,
-          sf_.name());
+      if (severity_) {
+        auto msg{
+            "Statement function '%s' should not reference a function that returns an array"_port_en_US};
+        msg.set_severity(*severity_);
+        return parser::Message{sf_.name(), std::move(msg), sf_.name()};
+      }
     }
     return std::nullopt;
   }
@@ -1083,9 +1114,12 @@ class StmtFunctionChecker
         return result;
       }
       if (expr->Rank() > 0 && !UnwrapWholeSymbolOrComponentDataRef(*expr)) {
-        return parser::Message(sf_.name(),
-            "Statement function '%s' should not pass an array argument that is not a whole array"_port_en_US,
-            sf_.name());
+        if (severity_) {
+          auto msg{
+              "Statement function '%s' should not pass an array argument that is not a whole array"_port_en_US};
+          msg.set_severity(*severity_);
+          return parser::Message{sf_.name(), std::move(msg), sf_.name()};
+        }
       }
     }
     return std::nullopt;
@@ -1094,6 +1128,7 @@ class StmtFunctionChecker
 private:
   const Symbol &sf_;
   FoldingContext &context_;
+  std::optional<parser::Severity> severity_;
 };
 
 std::optional<parser::Message> CheckStatementFunction(
diff --git a/flang/lib/Evaluate/intrinsics.cpp b/flang/lib/Evaluate/intrinsics.cpp
index c711b4feaca4831..52655cae8862b52 100644
--- a/flang/lib/Evaluate/intrinsics.cpp
+++ b/flang/lib/Evaluate/intrinsics.cpp
@@ -2224,12 +2224,15 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
         if (const Symbol *whole{
                 UnwrapWholeSymbolOrComponentDataRef(actualForDummy[*dimArg])}) {
           if (IsOptional(*whole) || IsAllocatableOrObjectPointer(whole)) {
-            if (rank == Rank::scalarIfDim || arrayRank.value_or(-1) == 1) {
-              messages.Say(
-                  "The actual argument for DIM= is optional, pointer, or allocatable, and it is assumed to be present and equal to 1 at execution time"_port_en_US);
-            } else {
-              messages.Say(
-                  "The actual argument for DIM= is optional, pointer, or allocatable, and may not be absent during execution; parenthesize to silence this warning"_warn_en_US);
+            if (context.languageFeatures().ShouldWarn(
+                    common::UsageWarning::DimMustBePresent)) {
+              if (rank == Rank::scalarIfDim || arrayRank.value_or(-1) == 1) {
+                messages.Say(
+                    "The actual argument for DIM= is optional, pointer, or allocatable, and it is assumed to be present and equal to 1 at execution time"_warn_en_US);
+              } else {
+                messages.Say(
+                    "The actual argument for DIM= is optional, pointer, or allocatable, and may not be absent during execution; parenthesize to silence this warning"_warn_en_US);
+              }
             }
           }
         }
@@ -3180,28 +3183,37 @@ std::optional<SpecificCall> IntrinsicProcTable::Implementation::Probe(
 
   // If there was no exact match with a specific, try to match the related
   // generic and convert the result to the specific required type.
-  for (auto specIter{specificRange.first}; specIter != specificRange.second;
-       ++specIter) {
-    // We only need to check the cases with distinct generic names.
-    if (const char *genericName{specIter->second->generic}) {
-      if (specIter->second->useGenericAndForceResultType) {
-        auto genericRange{genericFuncs_.equal_range(genericName)};
-        for (auto genIter{genericRange.first}; genIter != genericRange.second;
-             ++genIter) {
-          if (auto specificCall{
-                  matchOrBufferMessages(*genIter->second, specificBuffer)}) {
-            // Force the call result type to the specific intrinsic result type
-            DynamicType newType{GetReturnType(*specIter->second, defaults_)};
-            context.messages().Say(
-                "argument types do not match specific intrinsic '%s' "
-                "requirements; using '%s' generic instead and converting the "
-                "result to %s if needed"_port_en_US,
-                call.name, genericName, newType.AsFortran());
-            specificCall->specificIntrinsic.name = call.name;
-            specificCall->specificIntrinsic.characteristics.value()
-                .functionResult.value()
-                .SetType(newType);
-            return specificCall;
+  if (context.languageFeatures().IsEnabled(common::LanguageFeature::
+              UseGenericIntrinsicWhenSpecificDoesntMatch)) {
+    for (auto specIter{specificRange.first}; specIter != specificRange.second;
+         ++specIter) {
+      // We only need to check the cases with distinct generic names.
+      if (const char *genericName{specIter->second->generic}) {
+        if (specIter->second->useGenericAndForceResultType) {
+          auto genericRange{genericFuncs_.equal_range(genericName)};
+          for (auto genIter{genericRange.first}; genIter != genericRange.second;
+               ++genIter) {
+            if (auto specificCall{
+                    matchOrBufferMessages(*genIter->second, specificBuffer)}) {
+              // Force the call result type to the specific intrinsic result
+              // type
+              DynamicType newType{GetReturnType(*specIter->second, defaults_)};
+              if (context.languageFeatures().ShouldWarn(
+                      common::LanguageFeature::
+                          UseGenericIntrinsicWhenSpecificDoesntMatch)) {
+                context.messages().Say(
+                    "Argument types do not match specific intrinsic '%s' "
+                    "requirements; using '%s' generic instead and converting "
+                    "the "
+                    "result to %s if needed"_port_en_US,
+                    call.name, genericName, newType.AsFortran());
+              }
+              specificCall->specificIntrinsic.name = call.name;
+              specificCall->specificIntrinsic.characteristics.value()
+                  .functionResult.value()
+                  .SetType(newType);
+              return specificCall;
+            }
           }
         }
       }
diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp
index 73c00c8679c7ec6..f09e62148e53c53 100644
--- a/flang/lib/Frontend/FrontendActions.cpp
+++ b/flang/lib/Frontend/FrontendActions.cpp
@@ -278,7 +278,8 @@ bool CodeGenAction::beginSourceFileAction() {
       ci.getInvocation().getSemanticsContext().targetCharacteristics(),
       ci.getParsing().allCooked(), ci.getInvocation().getTargetOpts().triple,
       kindMap, ci.getInvocation().getLoweringOpts(),
-      ci.getInvocation().getFrontendOpts().envDefaults);
+      ci.getInvocation().getFrontendOpts().envDefaults,
+      ci.getInvocation().getFrontendOpts().features);
 
   // Fetch module from lb, so we can set
   mlirModule = std::make_unique<mlir::ModuleOp>(lb.getModule());
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 9875e37393ef869..f64719b64f12e5a 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -4901,7 +4901,8 @@ class FirConverter : public Fortran::lower::AbstractConverter {
 
 Fortran::evaluate::FoldingContext
 Fortran::lower::LoweringBridge::createFoldingContext() const {
-  return {getDefaultKinds(), getIntrinsicTable(), getTargetCharacteristics()};
+  return {getDefaultKinds(), getIntrinsicTable(), getTargetCharacteristics(),
+          getLanguageFeatures()};
 }
 
 void Fortran::lower::LoweringBridge::lower(
@@ -4931,11 +4932,13 @@ Fortran::lower::LoweringBridge::LoweringBridge(
     const Fortran::parser::AllCookedSources &cooked, llvm::StringRef triple,
     fir::KindMapping &kindMap,
     const Fortran::lower::LoweringOptions &loweringOptions,
-    const std::vector<Fortran::lower::EnvironmentDefault> &envDefaults)
+    const std::vector<Fortran::lower::EnvironmentDefault> &envDefaults,
+    const Fortran::common::LanguageFeatureControl &languageFeatures)
     : semanticsContext{semanticsContext}, defaultKinds{defaultKinds},
       intrinsics{intrinsics}, targetCharacteristics{targetCharacteristics},
       cooked{&cooked}, context{context}, kindMap{kindMap},
-      loweringOptions{loweringOptions}, envDefaults{envDefaults} {
+      loweringOptions{loweringOptions}, envDefaults{envDefaults},
+      languageFeatures{languageFeatures} {
   // Register the diagnostic handler.
   context.getDiagEngine().registerHandler([](mlir::Diagnostic &diag) {
     llvm::raw_ostream &os = llvm::errs();
diff --git a/flang/lib/Parser/expr-parsers.cpp b/flang/lib/Parser/expr-parsers.cpp
index 45e6b2869c02bd4..b27366d02308eb5 100644
--- a/flang/lib/Parser/expr-parsers.cpp
+++ b/flang/lib/Parser/expr-parsers.cpp
@@ -77,10 +77,8 @@ constexpr auto primary{instrumented("primary"_en_US,
         construct<Expr>(Parser<StructureConstructor>{}),
         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)))),
+        construct<Expr>(parenthesized(
+            construct<Expr::ComplexConstructor>(expr, "," >> expr))),
         extension<LanguageFeature::PercentLOC>(
             "nonstandard usage: %LOC"_port_en_US,
       ...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/71857


More information about the flang-commits mailing list