[flang-commits] [flang] 92da80b - [Flang][#212316] Fix -Wunused-template errors under -Werror (#218985)

via flang-commits flang-commits at lists.llvm.org
Tue Oct 6 09:47:42 PDT 2026


Author: laoshd
Date: 2026-10-06T16:47:28Z
New Revision: 92da80b7fdc6c5e8bbbecc46f43c9d27c222f401

URL: https://github.com/llvm/llvm-project/commit/92da80b7fdc6c5e8bbbecc46f43c9d27c222f401
DIFF: https://github.com/llvm/llvm-project/commit/92da80b7fdc6c5e8bbbecc46f43c9d27c222f401.diff

LOG: [Flang][#212316] Fix -Wunused-template errors under -Werror (#218985)

Some function templates with internal linkage are never instantiated in
their translation unit, which triggers -Wunused-template. When the
warning (-Wunused-template) and warning as error (-Werror, e.g.
-DFLANG_ENABLE_WERROR=ON) are enabled, these become fatal errors.

Fix each case with the minimal change that preserves semantics, and
remove unused templates:
- Drop 'static' (give external linkage) for free function templates at
namespace/file scope: DirectivesCommon.h, PFTBuilder.h, RTBuilder.h,
fold-reduction.h.
- Add [[maybe_unused]] where dropping 'static' would change linkage/ODR
semantics (member, anonymous-namespace, or global generic-named
templates): check-cuda.cpp, tools.cpp.
- Remove unused templates: formatting.cpp, CUFAllocationConversion.cpp,
resolve-directives.cpp, ConvertType.cpp, IO.cpp, openmp-utils.cpp.

Behavior is unchanged, while selected template linkage is intentionally
changed. With AI assistance.

Fixes #212316.

---------

Co-authored-by: Copilot <223556219+Copilot at users.noreply.github.com>
Co-authored-by: Aiden Grossman <aidengrossman at google.com>

Added: 
    

Modified: 
    flang/include/flang/Lower/DirectivesCommon.h
    flang/include/flang/Lower/PFTBuilder.h
    flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h
    flang/lib/Evaluate/fold-reduction.h
    flang/lib/Evaluate/formatting.cpp
    flang/lib/Evaluate/tools.cpp
    flang/lib/Lower/ConvertType.cpp
    flang/lib/Lower/IO.cpp
    flang/lib/Optimizer/Transforms/CUDA/CUFAllocationConversion.cpp
    flang/lib/Semantics/check-cuda.cpp
    flang/lib/Semantics/check-omp-syntax.cpp
    flang/lib/Semantics/openmp-utils.cpp
    flang/lib/Semantics/resolve-directives.cpp

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Lower/DirectivesCommon.h b/flang/include/flang/Lower/DirectivesCommon.h
index 6f6089a4ffb6cb..0d436bc61a51c3 100644
--- a/flang/include/flang/Lower/DirectivesCommon.h
+++ b/flang/include/flang/Lower/DirectivesCommon.h
@@ -75,15 +75,15 @@ getDataOperandBaseAddr(Fortran::lower::AbstractConverter &converter,
 
 namespace detail {
 template <typename T> //
-static T &&AsRvalueRef(T &&t) {
+T &&AsRvalueRef(T &&t) {
   return std::move(t);
 }
 template <typename T> //
-static T AsRvalueRef(T &t) {
+T AsRvalueRef(T &t) {
   return t;
 }
 template <typename T> //
-static T AsRvalueRef(const T &t) {
+T AsRvalueRef(const T &t) {
   return t;
 }
 

diff  --git a/flang/include/flang/Lower/PFTBuilder.h b/flang/include/flang/Lower/PFTBuilder.h
index 0f3e3d44f88f95..981a78068c6589 100644
--- a/flang/include/flang/Lower/PFTBuilder.h
+++ b/flang/include/flang/Lower/PFTBuilder.h
@@ -906,7 +906,7 @@ struct Program {
 /// Helper to get location from FunctionLikeUnit/ModuleLikeUnit begin/end
 /// statements.
 template <typename T>
-static parser::CharBlock stmtSourceLoc(const T &stmt) {
+parser::CharBlock stmtSourceLoc(const T &stmt) {
   return stmt.visit(common::visitors{[](const auto &x) { return x.source; }});
 }
 

diff  --git a/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h b/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h
index e2131aa7708a3b..67bdf6867251a5 100644
--- a/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h
+++ b/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h
@@ -843,9 +843,9 @@ struct RuntimeTableEntry<RuntimeTableKey<KT>, RuntimeIdentifier<Cs...>> {
 /// Get (or generate) the MLIR FuncOp for a given runtime function. Its template
 /// argument is intended to be of the form: <mkRTKey(runtime function name)>.
 template <typename RuntimeEntry>
-static mlir::func::FuncOp getRuntimeFunc(mlir::Location loc,
-                                         fir::FirOpBuilder &builder,
-                                         bool isIO = false) {
+mlir::func::FuncOp getRuntimeFunc(mlir::Location loc,
+                                  fir::FirOpBuilder &builder,
+                                  bool isIO = false) {
   using namespace Fortran::runtime;
   auto name = RuntimeEntry::name;
   auto func = builder.getNamedFunction(name);
@@ -857,8 +857,8 @@ static mlir::func::FuncOp getRuntimeFunc(mlir::Location loc,
 
 /// Get (or generate) the MLIR FuncOp for a given IO runtime function.
 template <typename E>
-static mlir::func::FuncOp getIORuntimeFunc(mlir::Location loc,
-                                           fir::FirOpBuilder &builder) {
+mlir::func::FuncOp getIORuntimeFunc(mlir::Location loc,
+                                    fir::FirOpBuilder &builder) {
   return getRuntimeFunc<E>(loc, builder, /*isIO=*/true);
 }
 

diff  --git a/flang/lib/Evaluate/fold-reduction.h b/flang/lib/Evaluate/fold-reduction.h
index a068364135295f..aef5e932872973 100644
--- a/flang/lib/Evaluate/fold-reduction.h
+++ b/flang/lib/Evaluate/fold-reduction.h
@@ -15,8 +15,7 @@ namespace Fortran::evaluate {
 
 // DOT_PRODUCT
 template <typename T>
-static Expr<T> FoldDotProduct(
-    FoldingContext &context, FunctionRef<T> &&funcRef) {
+Expr<T> FoldDotProduct(FoldingContext &context, FunctionRef<T> &&funcRef) {
   using Element = typename Constant<T>::Element;
   auto args{funcRef.arguments()};
   CHECK(args.size() == 2);
@@ -132,9 +131,9 @@ template <typename T> struct ArrayAndMask {
   Constant<LogicalResult> mask;
 };
 template <typename T>
-static std::optional<ArrayAndMask<T>> ProcessReductionArgs(
-    FoldingContext &context, ActualArguments &arg, std::optional<int> &dim,
-    int arrayIndex, std::optional<int> dimIndex = std::nullopt,
+std::optional<ArrayAndMask<T>> ProcessReductionArgs(FoldingContext &context,
+    ActualArguments &arg, std::optional<int> &dim, int arrayIndex,
+    std::optional<int> dimIndex = std::nullopt,
     std::optional<int> maskIndex = std::nullopt) {
   if (arg.empty()) {
     return std::nullopt;
@@ -174,7 +173,7 @@ static std::optional<ArrayAndMask<T>> ProcessReductionArgs(
 // operator()(Scalar<T> &, const ConstantSubscripts &, bool first)
 // and Done(Scalar<T> &).
 template <typename T, typename ACCUMULATOR, typename ARRAY>
-static Constant<T> DoReduction(const Constant<ARRAY> &array,
+Constant<T> DoReduction(const Constant<ARRAY> &array,
     const Constant<LogicalResult> &mask, std::optional<int> &dim,
     const Scalar<T> &identity, ACCUMULATOR &accumulator) {
   ConstantSubscripts at{array.lbounds()};
@@ -265,7 +264,7 @@ template <typename T, bool ABS = false> class MaxvalMinvalAccumulator {
 };
 
 template <typename T>
-static Expr<T> FoldMaxvalMinval(FoldingContext &context, FunctionRef<T> &&ref,
+Expr<T> FoldMaxvalMinval(FoldingContext &context, FunctionRef<T> &&ref,
     RelationalOperator opr, const Scalar<T> &identity) {
   static_assert(T::category == TypeCategory::Integer ||
       T::category == TypeCategory::Unsigned ||
@@ -309,7 +308,7 @@ template <typename T> class ProductAccumulator {
 };
 
 template <typename T>
-static Expr<T> FoldProduct(
+Expr<T> FoldProduct(
     FoldingContext &context, FunctionRef<T> &&ref, Scalar<T> identity) {
   static_assert(T::category == TypeCategory::Integer ||
       T::category == TypeCategory::Unsigned ||
@@ -371,7 +370,7 @@ template <typename T> class SumAccumulator {
 };
 
 template <typename T>
-static Expr<T> FoldSum(FoldingContext &context, FunctionRef<T> &&ref) {
+Expr<T> FoldSum(FoldingContext &context, FunctionRef<T> &&ref) {
   static_assert(T::category == TypeCategory::Integer ||
       T::category == TypeCategory::Unsigned ||
       T::category == TypeCategory::Real ||

diff  --git a/flang/lib/Evaluate/formatting.cpp b/flang/lib/Evaluate/formatting.cpp
index fcedd15ee17913..161372e3ab61bb 100644
--- a/flang/lib/Evaluate/formatting.cpp
+++ b/flang/lib/Evaluate/formatting.cpp
@@ -414,22 +414,6 @@ template <typename T> static Precedence ToPrecedence(const Expr<T> &expr) {
   return common::visit([](const auto &x) { return ToPrecedence(x); }, expr.u);
 }
 
-template <typename T> static bool IsNegatedScalarConstant(const Expr<T> &expr) {
-  static constexpr TypeCategory cat{T::category};
-  if constexpr (cat == TypeCategory::Integer || cat == TypeCategory::Real) {
-    if (auto n{GetScalarConstantValue<T>(expr)}) {
-      return n->IsNegative();
-    }
-  }
-  return false;
-}
-
-template <TypeCategory CAT>
-static bool IsNegatedScalarConstant(const Expr<SomeKind<CAT>> &expr) {
-  return common::visit(
-      [](const auto &x) { return IsNegatedScalarConstant(x); }, expr.u);
-}
-
 struct OperatorSpelling {
   const char *prefix{""}, *infix{","}, *suffix{""};
 };

diff  --git a/flang/lib/Evaluate/tools.cpp b/flang/lib/Evaluate/tools.cpp
index b02dcc5318ded6..0010221083d1e5 100644
--- a/flang/lib/Evaluate/tools.cpp
+++ b/flang/lib/Evaluate/tools.cpp
@@ -1552,11 +1552,6 @@ static SignedNumericExpr<CAT, KIND> buildSignedAdd(
       true};
 }
 
-template <typename T>
-static std::optional<Expr<SomeType>> tryBuildSplitSumExpressionTree(const T &) {
-  return std::nullopt;
-}
-
 template <common::TypeCategory CAT, int KIND>
 static std::optional<NumericExpr<CAT, KIND>> tryBuildSplitSumExpressionTree(
     const NumericExpr<CAT, KIND> &expr) {
@@ -1602,24 +1597,6 @@ static std::optional<NumericExpr<CAT, KIND>> tryBuildSplitSumExpressionTree(
   return std::move(result.expr);
 }
 
-template <common::TypeCategory CAT>
-static std::optional<Expr<SomeType>> tryBuildSplitSumExpressionTree(
-    const Expr<SomeKind<CAT>> &expr) {
-  // Keep the supported categories explicit: integer reassociation requires a
-  // separate intermediate-range policy.
-  if constexpr (CAT == common::TypeCategory::Real ||
-      CAT == common::TypeCategory::Complex) {
-    return common::visit(
-        [&](const auto &typedExpr) -> std::optional<Expr<SomeType>> {
-          if (auto result = tryBuildSplitSumExpressionTree(typedExpr))
-            return Expr<SomeType>{std::move(*result)};
-          return std::nullopt;
-        },
-        expr.u);
-  }
-  return std::nullopt;
-}
-
 template <typename> struct IsExpr : std::false_type {};
 template <typename T> struct IsExpr<Expr<T>> : std::true_type {};
 

diff  --git a/flang/lib/Lower/ConvertType.cpp b/flang/lib/Lower/ConvertType.cpp
index 0fdbdfcc744243..c8253ba25fc6f2 100644
--- a/flang/lib/Lower/ConvertType.cpp
+++ b/flang/lib/Lower/ConvertType.cpp
@@ -535,11 +535,6 @@ struct TypeBuilderImpl {
     llvm_unreachable("unknown character kind");
   }
 
-  template <typename A>
-  Fortran::lower::LenParameterTy getCharacterLength(const A &expr) {
-    return fir::SequenceType::getUnknownExtent();
-  }
-
   template <typename T>
   Fortran::lower::LenParameterTy
   getCharacterLength(const Fortran::evaluate::FunctionRef<T> &funcRef) {

diff  --git a/flang/lib/Lower/IO.cpp b/flang/lib/Lower/IO.cpp
index 5636f9e25b9909..30bc0c52ec2229 100644
--- a/flang/lib/Lower/IO.cpp
+++ b/flang/lib/Lower/IO.cpp
@@ -45,50 +45,6 @@ using namespace Fortran::runtime::io;
 
 #define mkIOKey(X) FirmkKey(IONAME(X))
 
-namespace Fortran::lower {
-/// Static table of IO runtime calls
-///
-/// This logical map contains the name and type builder function for each IO
-/// runtime function listed in the tuple. This table is fully constructed at
-/// compile-time. Use the `mkIOKey` macro to access the table.
-static constexpr std::tuple<
-    mkIOKey(BeginBackspace), mkIOKey(BeginClose), mkIOKey(BeginEndfile),
-    mkIOKey(BeginExternalFormattedInput), mkIOKey(BeginExternalFormattedOutput),
-    mkIOKey(BeginExternalListInput), mkIOKey(BeginExternalListOutput),
-    mkIOKey(BeginFlush), mkIOKey(BeginInquireFile),
-    mkIOKey(BeginInquireIoLength), mkIOKey(BeginInquireUnit),
-    mkIOKey(BeginInternalArrayFormattedInput),
-    mkIOKey(BeginInternalArrayFormattedOutput),
-    mkIOKey(BeginInternalArrayListInput), mkIOKey(BeginInternalArrayListOutput),
-    mkIOKey(BeginInternalFormattedInput), mkIOKey(BeginInternalFormattedOutput),
-    mkIOKey(BeginInternalListInput), mkIOKey(BeginInternalListOutput),
-    mkIOKey(BeginOpenNewUnit), mkIOKey(BeginOpenUnit), mkIOKey(BeginRewind),
-    mkIOKey(BeginUnformattedInput), mkIOKey(BeginUnformattedOutput),
-    mkIOKey(BeginWait), mkIOKey(BeginWaitAll),
-    mkIOKey(CheckUnitNumberInRange64), mkIOKey(CheckUnitNumberInRange128),
-    mkIOKey(EnableHandlers), mkIOKey(EndIoStatement),
-    mkIOKey(GetAsynchronousId), mkIOKey(GetIoLength), mkIOKey(GetIoMsg),
-    mkIOKey(GetNewUnit), mkIOKey(GetSize), mkIOKey(InputAscii),
-    mkIOKey(InputComplex32), mkIOKey(InputComplex64), mkIOKey(InputDerivedType),
-    mkIOKey(InputDescriptor), mkIOKey(InputInteger), mkIOKey(InputLogical),
-    mkIOKey(InputNamelist), mkIOKey(InputReal32), mkIOKey(InputReal64),
-    mkIOKey(InquireCharacter), mkIOKey(InquireInteger64),
-    mkIOKey(InquireLogical), mkIOKey(InquirePendingId), mkIOKey(OutputAscii),
-    mkIOKey(OutputComplex32), mkIOKey(OutputComplex64),
-    mkIOKey(OutputDerivedType), mkIOKey(OutputDescriptor),
-    mkIOKey(OutputInteger8), mkIOKey(OutputInteger16), mkIOKey(OutputInteger32),
-    mkIOKey(OutputInteger64), mkIOKey(OutputInteger128), mkIOKey(OutputLogical),
-    mkIOKey(OutputNamelist), mkIOKey(OutputReal32), mkIOKey(OutputReal64),
-    mkIOKey(SetAccess), mkIOKey(SetAction), mkIOKey(SetAdvance),
-    mkIOKey(SetAsynchronous), mkIOKey(SetBlank), mkIOKey(SetCarriagecontrol),
-    mkIOKey(SetConvert), mkIOKey(SetDecimal), mkIOKey(SetDelim),
-    mkIOKey(SetEncoding), mkIOKey(SetFile), mkIOKey(SetForm),
-    mkIOKey(SetLeadingZero), mkIOKey(SetPad), mkIOKey(SetPos),
-    mkIOKey(SetPosition), mkIOKey(SetRec), mkIOKey(SetRecl), mkIOKey(SetRound),
-    mkIOKey(SetSign), mkIOKey(SetStatus)>
-    newIOTable;
-} // namespace Fortran::lower
-
 namespace {
 /// IO statements may require exceptional condition handling. A statement that
 /// encounters an exceptional condition may branch to a label given on an ERR
@@ -125,19 +81,6 @@ static void genIoLoop(Fortran::lower::AbstractConverter &converter,
                       bool isFormatted, bool checkResult, mlir::Value &ok,
                       bool inLoop);
 
-/// Helper function to retrieve the name of the IO function given the key `A`
-template <typename A>
-static constexpr const char *getName() {
-  return std::get<A>(Fortran::lower::newIOTable).name;
-}
-
-/// Helper function to retrieve the type model signature builder of the IO
-/// function as defined by the key `A`
-template <typename A>
-static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() {
-  return std::get<A>(Fortran::lower::newIOTable).getTypeModel();
-}
-
 inline int64_t getLength(mlir::Type argTy) {
   return mlir::cast<fir::SequenceType>(argTy).getShape()[0];
 }

diff  --git a/flang/lib/Optimizer/Transforms/CUDA/CUFAllocationConversion.cpp b/flang/lib/Optimizer/Transforms/CUDA/CUFAllocationConversion.cpp
index b75d289faca7a5..7d62e4ca1ec1a1 100644
--- a/flang/lib/Optimizer/Transforms/CUDA/CUFAllocationConversion.cpp
+++ b/flang/lib/Optimizer/Transforms/CUDA/CUFAllocationConversion.cpp
@@ -42,13 +42,6 @@ using namespace Fortran::runtime::cuda;
 
 namespace {
 
-template <typename OpTy>
-static bool isPinned(OpTy op) {
-  if (op.getDataAttr() && *op.getDataAttr() == cuf::DataAttribute::Pinned)
-    return true;
-  return false;
-}
-
 static inline unsigned getMemType(cuf::DataAttribute attr) {
   if (attr == cuf::DataAttribute::Device)
     return kMemTypeDevice;

diff  --git a/flang/lib/Semantics/check-cuda.cpp b/flang/lib/Semantics/check-cuda.cpp
index e83dbbe0100b78..d557fd2ba5eb71 100644
--- a/flang/lib/Semantics/check-cuda.cpp
+++ b/flang/lib/Semantics/check-cuda.cpp
@@ -304,8 +304,12 @@ static bool IsPlainScalar(const Symbol &symbol) {
       !ultimate.owner().IsDerivedType() && !IsAllocatableOrPointer(ultimate);
 }
 
+// [[maybe_unused]] works around a -Wunused-template false positive: this
+// overload is only reached through the if-constexpr-dispatched recursion in
+// ActionStmtChecker::WhyNotOk, a pattern Clang's use-tracking misses (see
+// llvm/llvm-project#218429). Remove once that is fixed upstream.
 template <typename A>
-static MaybeMsg CheckUnwrappedExpr(
+[[maybe_unused]] static MaybeMsg CheckUnwrappedExpr(
     SemanticsContext &context, const A &x, bool allowHostCallees = false) {
   if (const auto *expr{parser::Unwrap<parser::Expr>(x)}) {
     return DeviceExprChecker{context, allowHostCallees}(expr->typedExpr);

diff  --git a/flang/lib/Semantics/check-omp-syntax.cpp b/flang/lib/Semantics/check-omp-syntax.cpp
index 03f8e554be3502..d96d9670367f97 100644
--- a/flang/lib/Semantics/check-omp-syntax.cpp
+++ b/flang/lib/Semantics/check-omp-syntax.cpp
@@ -49,16 +49,6 @@ static llvm::omp::ModifierSets GetSets(
   return desc.getModifierSets(version);
 }
 
-template <typename DescriptorTy>
-static auto GetAllowedElements(
-    const DescriptorTy &desc, llvm::omp::Version version) {
-  auto allowed{GetElements(desc, version)};
-  for (auto s : GetSets(desc, version)) {
-    allowed |= GetElements(GetDescriptor(s), version);
-  }
-  return allowed;
-}
-
 template < //
     typename ElemTy, typename SetsSetTy, typename OwnerTy,
     typename ResultTy = llvm::DenseMap<ElemTy,

diff  --git a/flang/lib/Semantics/openmp-utils.cpp b/flang/lib/Semantics/openmp-utils.cpp
index 794a748592bced..16c265ce39690d 100644
--- a/flang/lib/Semantics/openmp-utils.cpp
+++ b/flang/lib/Semantics/openmp-utils.cpp
@@ -490,14 +490,6 @@ struct ContiguousHelper {
   ContiguousHelper(SemanticsContext &context)
       : fctx_(context.foldingContext()) {}
 
-  template <typename Contained>
-  std::optional<bool> Visit(const common::Indirection<Contained> &x) {
-    return Visit(x.value());
-  }
-  template <typename Contained>
-  std::optional<bool> Visit(const common::Reference<Contained> &x) {
-    return Visit(x.get());
-  }
   template <typename T> std::optional<bool> Visit(const evaluate::Expr<T> &x) {
     return common::visit([&](auto &&s) { return Visit(s); }, x.u);
   }

diff  --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index b6a3db9375faf7..d707ff836b146b 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -35,15 +35,6 @@
 
 namespace Fortran::semantics {
 
-template <typename T>
-static Scope *GetScope(SemanticsContext &context, const T &x) {
-  if (auto source{GetLastSource(x)}) {
-    return &context.FindScope(*source);
-  } else {
-    return nullptr;
-  }
-}
-
 template <typename T> class DirectiveAttributeVisitor {
 public:
   explicit DirectiveAttributeVisitor(SemanticsContext &context)


        


More information about the flang-commits mailing list