[flang-commits] [flang] fc9e6e1 - [flang] Represent use statement in fir. (#168106)
via flang-commits
flang-commits at lists.llvm.org
Fri Jan 2 04:10:22 PST 2026
Author: Abid Qadeer
Date: 2026-01-02T12:10:18Z
New Revision: fc9e6e13fd4bb7365e4b9659c08c3440688217ce
URL: https://github.com/llvm/llvm-project/commit/fc9e6e13fd4bb7365e4b9659c08c3440688217ce
DIFF: https://github.com/llvm/llvm-project/commit/fc9e6e13fd4bb7365e4b9659c08c3440688217ce.diff
LOG: [flang] Represent use statement in fir. (#168106)
We have a longstanding issue in debug info that use statement is not
fully respected. The problem has been described in
https://github.com/llvm/llvm-project/issues/160923. This is first part
of the effort to address this issue. This PR adds infrastructure to emit
`use` statement information in FIR, which will be used by subsequent
patches to generate DWARF debug information.
The information about use statement is collected during semantic
analysis and stored in `PreservedUseStmt` objects. During lowering,
`fir.use_stmt` operations are emitted for each `PreservedUseStmt`
object. The `fir.use_stmt` operation captures the module name, `only`
list symbols, and any renames specified in the use statement. The
`fir.use_stmt` is removed during `CodeGen`.
Added:
flang/test/Lower/debug-use-stmt.f90
Modified:
flang/include/flang/Lower/LoweringOptions.def
flang/include/flang/Lower/PFTBuilder.h
flang/include/flang/Optimizer/Dialect/FIRAttr.td
flang/include/flang/Optimizer/Dialect/FIROps.td
flang/include/flang/Semantics/scope.h
flang/lib/Frontend/CompilerInvocation.cpp
flang/lib/Frontend/ParserActions.cpp
flang/lib/Lower/Bridge.cpp
flang/lib/Lower/PFTBuilder.cpp
flang/lib/Optimizer/CodeGen/CodeGen.cpp
flang/lib/Semantics/resolve-names.cpp
flang/tools/bbc/bbc.cpp
Removed:
################################################################################
diff --git a/flang/include/flang/Lower/LoweringOptions.def b/flang/include/flang/Lower/LoweringOptions.def
index 39f197d8d35c8..9f76dcc15a2a3 100644
--- a/flang/include/flang/Lower/LoweringOptions.def
+++ b/flang/include/flang/Lower/LoweringOptions.def
@@ -79,5 +79,10 @@ ENUM_LOWERINGOPT(ComplexDivisionToRuntime, unsigned, 1, 1)
/// of the lowering pipeline.
ENUM_LOWERINGOPT(RegisterMLIRDiagnosticsHandler, unsigned, 1, 1)
+/// If true, preserve USE statement information during PFT building for
+/// debug info generation. Should be enabled when debug info level is above
+/// LineTablesOnly. Off by default.
+ENUM_LOWERINGOPT(PreserveUseDebugInfo, unsigned, 1, 0)
+
#undef LOWERINGOPT
#undef ENUM_LOWERINGOPT
diff --git a/flang/include/flang/Lower/PFTBuilder.h b/flang/include/flang/Lower/PFTBuilder.h
index ac87fcd7c3b9b..9cff324692341 100644
--- a/flang/include/flang/Lower/PFTBuilder.h
+++ b/flang/include/flang/Lower/PFTBuilder.h
@@ -737,6 +737,8 @@ struct FunctionLikeUnit : public ProgramUnit {
/// Terminal basic block (if any)
mlir::Block *finalBlock{};
HostAssociations hostAssociations;
+ /// Preserved USE statements for debug info generation
+ std::list<Fortran::semantics::PreservedUseStmt> preservedUseStmts;
};
/// Module-like units contain a list of function-like units.
@@ -866,6 +868,8 @@ void visitAllSymbols(const Evaluation &eval,
} // namespace Fortran::lower::pft
namespace Fortran::lower {
+class LoweringOptions;
+
/// Create a PFT (Pre-FIR Tree) from the parse tree.
///
/// A PFT is a light weight tree over the parse tree that is used to create FIR.
@@ -876,7 +880,8 @@ namespace Fortran::lower {
/// either a statement, or a construct with a nested list of evaluations.
std::unique_ptr<pft::Program>
createPFT(const parser::Program &root,
- const Fortran::semantics::SemanticsContext &semanticsContext);
+ const Fortran::semantics::SemanticsContext &semanticsContext,
+ const LoweringOptions &loweringOptions);
/// Dumper for displaying a PFT.
void dumpPFT(llvm::raw_ostream &outputStream, const pft::Program &pft);
diff --git a/flang/include/flang/Optimizer/Dialect/FIRAttr.td b/flang/include/flang/Optimizer/Dialect/FIRAttr.td
index 5e3185480a7eb..2fbe195ee9f33 100644
--- a/flang/include/flang/Optimizer/Dialect/FIRAttr.td
+++ b/flang/include/flang/Optimizer/Dialect/FIRAttr.td
@@ -243,4 +243,21 @@ def fir_FortranInlineAttr
: EnumAttr<FIROpsDialect, fir_FortranInlineEnum, "inline_attrs"> {
let assemblyFormat = "`<` $value `>`";
}
+
+// USE statement rename mapping: local_name => use_name
+def fir_UseRenameAttr : fir_Attr<"UseRename"> {
+ let mnemonic = "use_rename";
+ let summary = "Represents a rename in a Fortran USE statement";
+ let description = [{
+ This attribute stores the mapping for a renamed symbol in a USE statement.
+ For example, in "USE mod, local_var => module_var", this stores the
+ local name and a symbol reference to the module variable.
+ }];
+
+ let parameters = (ins "mlir::StringAttr":$local_name,
+ "mlir::FlatSymbolRefAttr":$symbol);
+
+ let assemblyFormat = "`<` $local_name `,` $symbol `>`";
+}
+
#endif // FIR_DIALECT_FIR_ATTRS
diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.td b/flang/include/flang/Optimizer/Dialect/FIROps.td
index 7bfb304b973f5..126de599336a9 100644
--- a/flang/include/flang/Optimizer/Dialect/FIROps.td
+++ b/flang/include/flang/Optimizer/Dialect/FIROps.td
@@ -3102,6 +3102,58 @@ def fir_GlobalLenOp : fir_Op<"global_len", []> {
}];
}
+def fir_UseStmtOp
+ : fir_Op<"use_stmt", [MemoryEffects<[MemWrite<DebuggingResource>]>]> {
+ let summary = "Represents a Fortran USE statement";
+ let description = [{
+ This operation records a Fortran USE statement with its associated only/rename
+ information. It has no runtime effect but preserves semantic information for
+ debug information generation.
+
+ The operation captures:
+ - The module being used (via module_name string)
+ - Symbol references to symbols imported via the ONLY clause (if present)
+ - Symbol renames (local_name and symbol reference)
+
+ Examples:
+ ```
+ // USE mod1
+ fir.use_stmt "mod1"
+
+ // USE mod1, ONLY: var2
+ fir.use_stmt "mod1" only_symbols [@_QMmod1Evar2]
+
+ // USE mod2, var4 => var3
+ fir.use_stmt "mod2" renames [#fir.use_rename<"var4", @_QMmod2Evar3>]
+
+ // USE mod2, ONLY: var1, renamed => original
+ fir.use_stmt "mod2" only_symbols [@_QMmod2Evar1]
+ renames [#fir.use_rename<"renamed", @_QMmod2Eoriginal>]
+ ```
+ }];
+
+ let arguments = (ins StrAttr:$module_name,
+ OptionalAttr<ArrayAttr>:$only_symbols, OptionalAttr<ArrayAttr>:$renames);
+
+ let assemblyFormat = [{
+ $module_name
+ (`only_symbols` `[` $only_symbols^ `]`)?
+ (`renames` `[` $renames^ `]`)?
+ attr-dict
+ }];
+
+ let extraClassDeclaration = [{
+ /// Returns true if this is a USE with ONLY clause
+ bool hasOnlyClause() { return getOnlySymbols().has_value(); }
+
+ /// Returns true if this has any renames
+ bool hasRenames() { return getRenames().has_value(); }
+
+ /// Returns true if this imports the entire module (no ONLY clause)
+ bool importsAll() { return !hasOnlyClause(); }
+ }];
+}
+
def ImplicitFirTerminator : SingleBlockImplicitTerminator<"FirEndOp">;
def fir_TypeInfoOp : fir_Op<"type_info",
diff --git a/flang/include/flang/Semantics/scope.h b/flang/include/flang/Semantics/scope.h
index ecffdb468bf6c..16553fe692e79 100644
--- a/flang/include/flang/Semantics/scope.h
+++ b/flang/include/flang/Semantics/scope.h
@@ -55,6 +55,15 @@ struct EquivalenceObject {
};
using EquivalenceSet = std::vector<EquivalenceObject>;
+// Preserved USE statement information for debug info generation.
+struct PreservedUseStmt {
+ std::string moduleName;
+ std::vector<std::string> onlyNames; // For USE ONLY
+ std::vector<std::string> renames; // local_name (resolved via GetUltimate)
+
+ PreservedUseStmt(std::string modName) : moduleName(std::move(modName)) {}
+};
+
class Scope {
using mapType = std::map<SourceName, MutableSymbolRef>;
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
index dd25cdc0e5707..4fb1d91306745 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -1657,6 +1657,14 @@ bool CompilerInvocation::createFromArgs(
parsePreprocessorArgs(invoc.getPreprocessorOpts(), args);
parseCodeGenArgs(invoc.getCodeGenOpts(), args, diags);
success &= parseDebugArgs(invoc.getCodeGenOpts(), args, diags);
+
+ // Enable USE statement preservation for debug info if debug level is above
+ // LineTablesOnly.
+ using DebugInfoKind = llvm::codegenoptions::DebugInfoKind;
+ DebugInfoKind debugLevel = invoc.getCodeGenOpts().getDebugInfo();
+ invoc.loweringOpts.setPreserveUseDebugInfo(
+ debugLevel > DebugInfoKind::DebugLineTablesOnly);
+
success &= parseVectorLibArg(invoc.getCodeGenOpts(), args, diags);
success &= parseSemaArgs(invoc, args, diags);
success &= parseDialectArgs(invoc, args, diags);
diff --git a/flang/lib/Frontend/ParserActions.cpp b/flang/lib/Frontend/ParserActions.cpp
index 4fe575b06d29f..1722c7a9cf9d0 100644
--- a/flang/lib/Frontend/ParserActions.cpp
+++ b/flang/lib/Frontend/ParserActions.cpp
@@ -48,7 +48,10 @@ void dumpProvenance(CompilerInstance &ci) {
void dumpPreFIRTree(CompilerInstance &ci) {
auto &parseTree{*ci.getParsing().parseTree()};
- if (auto ast{lower::createPFT(parseTree, ci.getSemanticsContext())}) {
+ // Use default lowering options for PFT dump
+ lower::LoweringOptions loweringOptions{};
+ if (auto ast{lower::createPFT(parseTree, ci.getSemanticsContext(),
+ loweringOptions)}) {
lower::dumpPFT(llvm::outs(), *ast);
} else {
unsigned diagID = ci.getDiagnostics().getCustomDiagID(
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index d175e2a8a73cb..a322e46ed0b9b 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -222,6 +222,76 @@ static mlir::FlatSymbolRefAttr gatherComponentInit(
return mlir::FlatSymbolRefAttr::get(mlirContext, name);
}
+/// Emit fir.use_stmt operations for USE statements in the given function unit
+static void
+emitUseStatementsFromFunit(Fortran::lower::AbstractConverter &converter,
+ mlir::OpBuilder &builder, mlir::Location loc,
+ const Fortran::lower::pft::FunctionLikeUnit &funit) {
+ mlir::MLIRContext *context = builder.getContext();
+ const Fortran::semantics::Scope &scope = funit.getScope();
+
+ for (const auto &preservedStmt : funit.preservedUseStmts) {
+
+ auto getMangledName = [&](const std::string &localName) -> std::string {
+ Fortran::parser::CharBlock charBlock{localName.data(), localName.size()};
+ const auto *sym = scope.FindSymbol(charBlock);
+ if (!sym)
+ return "";
+
+ const auto &ultimateSym = sym->GetUltimate();
+
+ // Skip cases which can cause mangleName to fail.
+ if (ultimateSym.has<Fortran::semantics::DerivedTypeDetails>())
+ return "";
+
+ if (const auto *generic =
+ ultimateSym.detailsIf<Fortran::semantics::GenericDetails>()) {
+ if (!generic->specific())
+ return "";
+ }
+
+ return converter.mangleName(ultimateSym);
+ };
+
+ mlir::StringAttr moduleNameAttr =
+ mlir::StringAttr::get(context, preservedStmt.moduleName);
+
+ llvm::SmallVector<mlir::Attribute> onlySymbolAttrs;
+ llvm::SmallVector<mlir::Attribute> renameAttrs;
+
+ // Handle only
+ for (const auto &name : preservedStmt.onlyNames) {
+ std::string mangledName = getMangledName(name);
+ if (!mangledName.empty())
+ onlySymbolAttrs.push_back(
+ mlir::FlatSymbolRefAttr::get(context, mangledName));
+ }
+
+ // Handle renames
+ for (const auto &local : preservedStmt.renames) {
+ std::string mangledName = getMangledName(local);
+ if (!mangledName.empty()) {
+ auto localAttr = mlir::StringAttr::get(context, local);
+ auto symbolRef = mlir::FlatSymbolRefAttr::get(context, mangledName);
+ renameAttrs.push_back(
+ fir::UseRenameAttr::get(context, localAttr, symbolRef));
+ }
+ }
+
+ // Create optional array attributes
+ mlir::ArrayAttr onlySymbolsAttr =
+ onlySymbolAttrs.empty()
+ ? mlir::ArrayAttr()
+ : mlir::ArrayAttr::get(context, onlySymbolAttrs);
+ mlir::ArrayAttr renamesAttr =
+ renameAttrs.empty() ? mlir::ArrayAttr()
+ : mlir::ArrayAttr::get(context, renameAttrs);
+
+ fir::UseStmtOp::create(builder, loc, moduleNameAttr, onlySymbolsAttr,
+ renamesAttr);
+ }
+}
+
/// Helper class to generate the runtime type info global data and the
/// fir.type_info operations that contain the dipatch tables (if any).
/// The type info global data is required to describe the derived type to the
@@ -6285,6 +6355,9 @@ class FirConverter : public Fortran::lower::AbstractConverter {
mapDummiesAndResults(funit, callee);
+ // Emit USE statement operations for debug info generation
+ emitUseStatementsFromFunit(*this, *builder, toLocation(), funit);
+
// Map host associated symbols from parent procedure if any.
if (funit.parentHasHostAssoc())
funit.parentHostAssoc().internalProcedureBindings(*this, localSymbols);
@@ -7114,7 +7187,7 @@ void Fortran::lower::LoweringBridge::lower(
const Fortran::parser::Program &prg,
const Fortran::semantics::SemanticsContext &semanticsContext) {
std::unique_ptr<Fortran::lower::pft::Program> pft =
- Fortran::lower::createPFT(prg, semanticsContext);
+ Fortran::lower::createPFT(prg, semanticsContext, getLoweringOptions());
FirConverter converter{*this};
converter.run(*pft);
}
diff --git a/flang/lib/Lower/PFTBuilder.cpp b/flang/lib/Lower/PFTBuilder.cpp
index 80f31c2be91a8..2dc7032b85f42 100644
--- a/flang/lib/Lower/PFTBuilder.cpp
+++ b/flang/lib/Lower/PFTBuilder.cpp
@@ -8,6 +8,7 @@
#include "flang/Lower/PFTBuilder.h"
#include "flang/Lower/IntervalSet.h"
+#include "flang/Lower/LoweringOptions.h"
#include "flang/Lower/Support/Utils.h"
#include "flang/Parser/dump-parse-tree.h"
#include "flang/Parser/parse-tree-visitor.h"
@@ -73,10 +74,11 @@ void dumpScope(const semantics::Scope *scope, int depth = -1);
/// limit the bridge to one such instantiation.
class PFTBuilder {
public:
- PFTBuilder(const semantics::SemanticsContext &semanticsContext)
+ PFTBuilder(const semantics::SemanticsContext &semanticsContext,
+ const lower::LoweringOptions &loweringOptions)
: pgm{std::make_unique<lower::pft::Program>(
semanticsContext.GetCommonBlocks())},
- semanticsContext{semanticsContext} {
+ semanticsContext{semanticsContext}, loweringOptions{loweringOptions} {
lower::pft::PftNode pftRoot{*pgm.get()};
pftParentStack.push_back(pftRoot);
}
@@ -124,6 +126,10 @@ class PFTBuilder {
},
},
stmt.unwrapped.u);
+ } else if constexpr (std::is_same_v<T, parser::UseStmt>) {
+ // Process USE statement for debug info generation
+ processUseStmt(stmt.unwrapped);
+ return false;
}
}
return true;
@@ -202,6 +208,100 @@ class PFTBuilder {
exitConstructOrDirective();
}
+ /// Process USE statements for debug info generation.
+ /// Captures USE statement information and stores it in the current
+ /// FunctionLikeUnit for later use.
+ void processUseStmt(const parser::UseStmt &useStmt) {
+ if (!loweringOptions.getPreserveUseDebugInfo())
+ return;
+
+ // Only process USE statements in specification part of function-like units
+ if (specificationPartLevel == 0 || !currentFunctionUnit)
+ return;
+
+ std::string moduleName{useStmt.moduleName.source.ToString()};
+
+ if (const auto *onlyList{
+ std::get_if<std::list<parser::Only>>(&useStmt.u)}) {
+ // USE mod, ONLY: list
+ Fortran::semantics::PreservedUseStmt stmt{moduleName};
+
+ for (const auto &only : *onlyList) {
+ Fortran::common::visit(
+ Fortran::common::visitors{
+ [&](const parser::Rename &rename) {
+ // ONLY with rename: ONLY: local => use
+ Fortran::common::visit(
+ Fortran::common::visitors{
+ [&](const parser::Rename::Names &names) {
+ std::string localName{
+ std::get<0>(names.t).source.ToString()};
+ stmt.renames.push_back(localName);
+ },
+ [&](const parser::Rename::Operators &) {
+ // Operator renames - not commonly needed for debug
+ // info
+ },
+ },
+ rename.u);
+ },
+ [&](const parser::Name &name) {
+ // ONLY without rename: ONLY: name
+ stmt.onlyNames.push_back(name.source.ToString());
+ },
+ [&](const Fortran::common::Indirection<parser::GenericSpec>
+ &genericSpec) {
+ // Generic spec can contain a Name (for regular symbols) or
+ // operators
+ Fortran::common::visit(Fortran::common::visitors{
+ [&](const parser::Name &name) {
+ stmt.onlyNames.push_back(
+ name.source.ToString());
+ },
+ [&](const auto &) {
+ // Operators and special forms -
+ // not commonly needed for
+ // variable debug info
+ },
+ },
+ genericSpec.value().u);
+ },
+ },
+ only.u);
+ }
+
+ currentFunctionUnit->preservedUseStmts.push_back(std::move(stmt));
+ } else if (const auto *renameList{
+ std::get_if<std::list<parser::Rename>>(&useStmt.u)}) {
+ // USE mod with optional renames (not ONLY)
+ if (renameList->empty()) {
+ // USE mod (import all, no renames)
+ Fortran::semantics::PreservedUseStmt stmt{moduleName};
+ currentFunctionUnit->preservedUseStmts.push_back(std::move(stmt));
+ } else {
+ // USE mod, renames (import all with some renames)
+ Fortran::semantics::PreservedUseStmt stmt{moduleName};
+
+ for (const auto &rename : *renameList) {
+ Fortran::common::visit(
+ Fortran::common::visitors{
+ [&](const parser::Rename::Names &names) {
+ std::string localName{
+ std::get<0>(names.t).source.ToString()};
+ stmt.renames.push_back(localName);
+ },
+ [&](const parser::Rename::Operators &) {
+ // Operator renames - not commonly needed for debug info
+ },
+ },
+ rename.u);
+ }
+
+ currentFunctionUnit->preservedUseStmts.push_back(std::move(stmt));
+ }
+ }
+ }
+
template <typename A>
constexpr void Post(const A &) {
if constexpr (lower::pft::isFunctionLike<A>) {
@@ -378,11 +478,13 @@ class PFTBuilder {
containedUnitList = &unit.containedUnitList;
pushEvaluationList(&unit.evaluationList);
pftParentStack.emplace_back(unit);
+ currentFunctionUnit = &unit;
LLVM_DEBUG(dumpScope(&unit.getScope()));
return true;
}
void exitFunction() {
+ currentFunctionUnit = nullptr; // Clear when exiting function
rewriteIfGotos();
endFunctionBody();
analyzeBranches(nullptr, *evaluationListStack.back()); // add branch links
@@ -1124,6 +1226,7 @@ class PFTBuilder {
std::unique_ptr<lower::pft::Program> pgm;
std::vector<lower::pft::PftNode> pftParentStack;
const semantics::SemanticsContext &semanticsContext;
+ const lower::LoweringOptions &loweringOptions;
llvm::SmallVector<bool> containsStmtStack{};
lower::pft::ContainedUnitList *containedUnitList{};
@@ -1136,6 +1239,8 @@ class PFTBuilder {
std::map<std::string, lower::pft::Evaluation *> constructNameMap{};
int specificationPartLevel{};
lower::pft::Evaluation *lastLexicalEvaluation{};
+ /// Current function-like unit being processed (for USE statement tracking)
+ lower::pft::FunctionLikeUnit *currentFunctionUnit{nullptr};
};
#ifndef NDEBUG
@@ -1894,8 +1999,9 @@ bool Fortran::lower::pft::Variable::isRuntimeTypeInfoData() const {
std::unique_ptr<lower::pft::Program>
Fortran::lower::createPFT(const parser::Program &root,
- const semantics::SemanticsContext &semanticsContext) {
- PFTBuilder walker(semanticsContext);
+ const semantics::SemanticsContext &semanticsContext,
+ const LoweringOptions &loweringOptions) {
+ PFTBuilder walker(semanticsContext, loweringOptions);
Walk(root, walker);
return walker.result();
}
diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
index 55e885d46d351..6dff368b68254 100644
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
@@ -3462,6 +3462,20 @@ struct NoReassocOpConversion : public fir::FIROpConversion<fir::NoReassocOp> {
}
};
+/// Erase `fir.use_stmt` operations during LLVM lowering.
+/// These operations are only used for debug info generation by the
+/// AddDebugInfo pass and have no runtime representation.
+struct UseStmtOpConversion : public fir::FIROpConversion<fir::UseStmtOp> {
+ using FIROpConversion::FIROpConversion;
+
+ llvm::LogicalResult
+ matchAndRewrite(fir::UseStmtOp useStmt, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const override {
+ rewriter.eraseOp(useStmt);
+ return mlir::success();
+ }
+};
+
static void genCondBrOp(mlir::Location loc, mlir::Value cmp, mlir::Block *dest,
std::optional<mlir::ValueRange> destOps,
mlir::ConversionPatternRewriter &rewriter,
@@ -4449,8 +4463,9 @@ void fir::populateFIRToLLVMConversionPatterns(
SliceOpConversion, StoreOpConversion, StringLitOpConversion,
SubcOpConversion, TypeDescOpConversion, TypeInfoOpConversion,
UnboxCharOpConversion, UnboxProcOpConversion, UndefOpConversion,
- UnreachableOpConversion, XArrayCoorOpConversion, XEmboxOpConversion,
- XReboxOpConversion, ZeroOpConversion>(converter, options);
+ UnreachableOpConversion, UseStmtOpConversion, XArrayCoorOpConversion,
+ XEmboxOpConversion, XReboxOpConversion, ZeroOpConversion>(converter,
+ options);
// Patterns that are populated without a type converter do not trigger
// target materializations for the operands of the root op.
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index ea2a3e4fb053d..a4781c129f04d 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -3663,6 +3663,7 @@ void ModuleVisitor::Post(const parser::UseStmt &x) {
for (const auto &[name, symbol] : useModuleScope_->commonBlockUses()) {
currScope().AddCommonBlockUse(name, symbol->attrs(), symbol->GetUltimate());
}
+
useModuleScope_ = nullptr;
}
diff --git a/flang/test/Lower/debug-use-stmt.f90 b/flang/test/Lower/debug-use-stmt.f90
new file mode 100644
index 0000000000000..293b38c78e17a
--- /dev/null
+++ b/flang/test/Lower/debug-use-stmt.f90
@@ -0,0 +1,80 @@
+! RUN: %flang_fc1 -emit-hlfir -debug-info-kind=standalone %s -o - | FileCheck %s --check-prefix=WITH_DEBUG
+! RUN: %flang_fc1 -emit-hlfir %s -o - | FileCheck %s --check-prefix=NO_DEBUG
+! RUN: %flang_fc1 -emit-hlfir -debug-info-kind=line-tables-only %s -o - | FileCheck %s --check-prefix=NO_DEBUG
+
+module mod1
+ integer :: a = 10, b = 20, c = 30
+end module mod1
+
+module mod2
+ real :: x = 1.0, y = 2.0, z = 3.0
+end module mod2
+
+module mod3
+ logical :: flag = .true.
+end module mod3
+
+! Test 1: Program with USE ONLY and USE with renames
+program test_main
+ use mod1, only: b, c
+ use mod2, renamed_y => y
+ implicit none
+ print *, b, c, renamed_y
+end program
+
+! Test 2: Subroutine with USE (all) and
diff erent renames
+subroutine test_sub()
+ use mod1
+ use mod2, only: x
+ use mod3, my_flag => flag
+ implicit none
+ print *, a, b, c, x, my_flag
+end subroutine
+
+! Test 3: Function with multiple USE patterns
+function test_func() result(res)
+ use mod1, only: a
+ use mod2, renamed_x => x, renamed_z => z
+ use mod3
+ implicit none
+ integer :: res
+ res = a
+end function
+
+! Test 4: Subroutine with USE ONLY with renames (combined)
+subroutine test_only_rename()
+ use mod1, only: local_b => b, c, local_a => a
+ use mod2, only: local_x => x, local_y => y
+ implicit none
+ print *, local_a, local_b, c, local_x, local_y
+end subroutine
+
+! WITH_DEBUG-LABEL: func.func @_QQmain()
+! WITH_DEBUG-DAG: fir.use_stmt "mod1" only_symbols{{\[}}[@_QMmod1Eb, @_QMmod1Ec]]
+! WITH_DEBUG-DAG: fir.use_stmt "mod2" renames{{\[}}[#fir.use_rename<"renamed_y", @_QMmod2Ey>]]
+
+! NO_DEBUG-LABEL: func.func @_QQmain()
+! NO_DEBUG-NOT: fir.use_stmt
+
+! WITH_DEBUG-LABEL: func.func @_QPtest_sub()
+! WITH_DEBUG-DAG: fir.use_stmt "mod1"{{$}}
+! WITH_DEBUG-DAG: fir.use_stmt "mod2" only_symbols{{\[}}[@_QMmod2Ex]]
+! WITH_DEBUG-DAG: fir.use_stmt "mod3" renames{{\[}}[#fir.use_rename<"my_flag", @_QMmod3Eflag>]]
+
+! NO_DEBUG-LABEL: func.func @_QPtest_sub()
+! NO_DEBUG-NOT: fir.use_stmt
+
+! WITH_DEBUG-LABEL: func.func @_QPtest_func()
+! WITH_DEBUG-DAG: fir.use_stmt "mod1" only_symbols{{\[}}[@_QMmod1Ea]]
+! WITH_DEBUG-DAG: fir.use_stmt "mod2" renames{{\[}}[#fir.use_rename<"renamed_x", @_QMmod2Ex>, #fir.use_rename<"renamed_z", @_QMmod2Ez>]]
+! WITH_DEBUG-DAG: fir.use_stmt "mod3"{{$}}
+
+! NO_DEBUG-LABEL: func.func @_QPtest_func()
+! NO_DEBUG-NOT: fir.use_stmt
+
+! WITH_DEBUG-LABEL: func.func @_QPtest_only_rename()
+! WITH_DEBUG-DAG: fir.use_stmt "mod1" only_symbols{{\[}}[@_QMmod1Ec]] renames{{\[}}[#fir.use_rename<"local_b", @_QMmod1Eb>, #fir.use_rename<"local_a", @_QMmod1Ea>]]
+! WITH_DEBUG-DAG: fir.use_stmt "mod2" renames{{\[}}[#fir.use_rename<"local_x", @_QMmod2Ex>, #fir.use_rename<"local_y", @_QMmod2Ey>]]
+
+! NO_DEBUG-LABEL: func.func @_QPtest_only_rename()
+! NO_DEBUG-NOT: fir.use_stmt
diff --git a/flang/tools/bbc/bbc.cpp b/flang/tools/bbc/bbc.cpp
index 8b12da3a7b50a..607ac5c82cec4 100644
--- a/flang/tools/bbc/bbc.cpp
+++ b/flang/tools/bbc/bbc.cpp
@@ -418,7 +418,10 @@ static llvm::LogicalResult convertFortranSourceToMLIR(
}
if (pftDumpTest) {
- if (auto ast = Fortran::lower::createPFT(parseTree, semanticsContext)) {
+ // Use default lowering options for PFT dump test
+ Fortran::lower::LoweringOptions loweringOptions{};
+ if (auto ast = Fortran::lower::createPFT(parseTree, semanticsContext,
+ loweringOptions)) {
Fortran::lower::dumpPFT(llvm::outs(), *ast);
return mlir::success();
}
More information about the flang-commits
mailing list