[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