[clang] dc256a4 - [flang][driver] Add support for `-fget-definition`
Andrzej Warzynski via cfe-commits
cfe-commits at lists.llvm.org
Wed Apr 21 02:31:53 PDT 2021
Author: Andrzej Warzynski
Date: 2021-04-21T09:31:36Z
New Revision: dc256a443a456a8e0e4d72736fee1c9442bcf4bd
URL: https://github.com/llvm/llvm-project/commit/dc256a443a456a8e0e4d72736fee1c9442bcf4bd
DIFF: https://github.com/llvm/llvm-project/commit/dc256a443a456a8e0e4d72736fee1c9442bcf4bd.diff
LOG: [flang][driver] Add support for `-fget-definition`
This patch adds `-fget-definition` to `flang-new`. The semantics of this
option are identical in both drivers. The error message in the
"throwaway" driver is updated so that it matches the one from
`flang-new` (which is auto-generated and cannot be changed easily).
Tests are updated accordingly. A dedicated test for error handling was
added: get-definition.f90 (for the sake of simplicity,
getdefinition01.f90 no longer tests for errors).
The `ParseFrontendArgs` function is updated so that it can return
errors. This change is required in order to report invalid values
following `-fget-definition`.
The actual implementation of `GetDefinitionAction::ExecuteAction()` was
extracted from f18.cpp (i.e. the bit that deals with
`-fget-definition`).
Depends on: https://reviews.llvm.org/D100556
Differential Revision: https://reviews.llvm.org/D100558
Added:
flang/test/Driver/get-definition.f90
Modified:
clang/include/clang/Driver/Options.td
flang/include/flang/Frontend/FrontendActions.h
flang/include/flang/Frontend/FrontendOptions.h
flang/lib/Frontend/CompilerInvocation.cpp
flang/lib/Frontend/FrontendActions.cpp
flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
flang/test/Driver/driver-help.f90
flang/test/Semantics/getdefinition01.f90
flang/test/Semantics/getdefinition02.f
flang/test/Semantics/getdefinition03-a.f90
flang/test/Semantics/getdefinition04.f90
flang/test/Semantics/getdefinition05.f90
flang/tools/f18/f18.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index f93b8a2496e07..648cfb0522e14 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -4381,6 +4381,9 @@ def J : JoinedOrSeparate<["-"], "J">,
//===----------------------------------------------------------------------===//
let Flags = [FC1Option, FlangOnlyOption] in {
+def fget_definition : MultiArg<["-"], "fget-definition", 3>,
+ HelpText<"Get the symbol definition from <line> <start-column> <end-column>">,
+ Group<Action_Group>;
def test_io : Flag<["-"], "test-io">, Group<Action_Group>,
HelpText<"Run the InputOuputTest action. Use for development and testing only.">;
def fdebug_unparse_no_sema : Flag<["-"], "fdebug-unparse-no-sema">, Group<Action_Group>,
diff --git a/flang/include/flang/Frontend/FrontendActions.h b/flang/include/flang/Frontend/FrontendActions.h
index 83e9652153ae3..619e83ad88c77 100644
--- a/flang/include/flang/Frontend/FrontendActions.h
+++ b/flang/include/flang/Frontend/FrontendActions.h
@@ -116,6 +116,10 @@ class DebugPreFIRTreeAction : public PrescanAndSemaAction {
void ExecuteAction() override;
};
+class GetDefinitionAction : public PrescanAndSemaAction {
+ void ExecuteAction() override;
+};
+
class GetSymbolsSourcesAction : public PrescanAndSemaAction {
void ExecuteAction() override;
};
diff --git a/flang/include/flang/Frontend/FrontendOptions.h b/flang/include/flang/Frontend/FrontendOptions.h
index 24fbdd3aff2a9..e18fd961a55b0 100644
--- a/flang/include/flang/Frontend/FrontendOptions.h
+++ b/flang/include/flang/Frontend/FrontendOptions.h
@@ -67,6 +67,9 @@ enum ActionKind {
/// Parse, run semantics and then output the pre-FIR tree
DebugPreFIRTree,
+ /// `-fget-definition`
+ GetDefinition,
+
/// Parse, run semantics and then dump symbol sources map
GetSymbolsSources
@@ -206,6 +209,14 @@ class FrontendOptions {
/// compilation.
unsigned needProvenanceRangeToCharBlockMappings_ : 1;
+ /// Input values from `-fget-definition`
+ struct GetDefinitionVals {
+ unsigned line;
+ unsigned startColumn;
+ unsigned endColumn;
+ };
+ GetDefinitionVals getDefVals_;
+
/// The input files and their types.
std::vector<FrontendInputFile> inputs_;
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
index a8879294eebf7..c79c2f2a0d939 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -95,12 +95,14 @@ static void setUpFrontendBasedOnAction(FrontendOptions &opts) {
if (opts.programAction_ == DebugDumpParsingLog)
opts.instrumentedParse_ = true;
- if (opts.programAction_ == DebugDumpProvenance)
+ if (opts.programAction_ == DebugDumpProvenance ||
+ opts.programAction_ == Fortran::frontend::GetDefinition)
opts.needProvenanceRangeToCharBlockMappings_ = true;
}
-static void ParseFrontendArgs(FrontendOptions &opts, llvm::opt::ArgList &args,
+static bool ParseFrontendArgs(FrontendOptions &opts, llvm::opt::ArgList &args,
clang::DiagnosticsEngine &diags) {
+ unsigned numErrorsBefore = diags.getNumErrors();
// By default the frontend driver creates a ParseSyntaxOnly action.
opts.programAction_ = ParseSyntaxOnly;
@@ -157,6 +159,9 @@ static void ParseFrontendArgs(FrontendOptions &opts, llvm::opt::ArgList &args,
case clang::driver::options::OPT_fget_symbols_sources:
opts.programAction_ = GetSymbolsSources;
break;
+ case clang::driver::options::OPT_fget_definition:
+ opts.programAction_ = GetDefinition;
+ break;
// TODO:
// case calng::driver::options::OPT_emit_llvm:
@@ -165,6 +170,27 @@ static void ParseFrontendArgs(FrontendOptions &opts, llvm::opt::ArgList &args,
// case clang::driver::options::OPT_emit_module:
// (...)
}
+
+ // Parse the values provided with `-fget-definition` (there should be 3
+ // integers)
+ if (llvm::opt::OptSpecifier(a->getOption().getID()) ==
+ clang::driver::options::OPT_fget_definition) {
+ unsigned optVals[3] = {0, 0, 0};
+
+ for (unsigned i = 0; i < 3; i++) {
+ llvm::StringRef val = a->getValue(i);
+
+ if (val.getAsInteger(10, optVals[i])) {
+ // A non-integer was encountered - that's an error.
+ diags.Report(clang::diag::err_drv_invalid_value)
+ << a->getOption().getName() << val;
+ break;
+ }
+ }
+ opts.getDefVals_.line = optVals[0];
+ opts.getDefVals_.startColumn = optVals[1];
+ opts.getDefVals_.endColumn = optVals[2];
+ }
}
opts.outputFile_ = args.getLastArgValue(clang::driver::options::OPT_o);
@@ -293,6 +319,8 @@ static void ParseFrontendArgs(FrontendOptions &opts, llvm::opt::ArgList &args,
setUpFrontendBasedOnAction(opts);
opts.dashX_ = dashX;
+
+ return diags.getNumErrors() == numErrorsBefore;
}
// Generate the path to look for intrinsic modules
@@ -481,8 +509,7 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &res,
success = false;
}
- // Parse the frontend args
- ParseFrontendArgs(res.frontendOpts(), args, diags);
+ success &= ParseFrontendArgs(res.frontendOpts(), args, diags);
parsePreprocessorArgs(res.preprocessorOpts(), args);
success &= parseSemaArgs(res, args, diags);
success &= parseDialectArgs(res, args, diags);
diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp
index 00b46c90dfd1f..f35ee4ed58e65 100644
--- a/flang/lib/Frontend/FrontendActions.cpp
+++ b/flang/lib/Frontend/FrontendActions.cpp
@@ -21,6 +21,7 @@
#include "flang/Semantics/semantics.h"
#include "flang/Semantics/unparse-with-symbols.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/ErrorHandling.h"
#include <clang/Basic/Diagnostic.h>
#include <memory>
@@ -371,6 +372,53 @@ void DebugDumpParsingLogAction::ExecuteAction() {
ci.parsing().DumpParsingLog(llvm::outs());
}
+void GetDefinitionAction::ExecuteAction() {
+ // Report and exit if fatal semantic errors are present
+ if (reportFatalSemanticErrors(semantics(), this->instance().diagnostics(),
+ GetCurrentFileOrBufferName()))
+ return;
+
+ CompilerInstance &ci = this->instance();
+ parser::AllCookedSources &cs = ci.allCookedSources();
+ unsigned diagID = ci.diagnostics().getCustomDiagID(
+ clang::DiagnosticsEngine::Error, "Symbol not found");
+
+ auto gdv = ci.invocation().frontendOpts().getDefVals_;
+ auto charBlock{cs.GetCharBlockFromLineAndColumns(
+ gdv.line, gdv.startColumn, gdv.endColumn)};
+ if (!charBlock) {
+ ci.diagnostics().Report(diagID);
+ return;
+ }
+
+ llvm::outs() << "String range: >" << charBlock->ToString() << "<\n";
+
+ auto *symbol{ci.invocation()
+ .semanticsContext()
+ .FindScope(*charBlock)
+ .FindSymbol(*charBlock)};
+ if (!symbol) {
+ ci.diagnostics().Report(diagID);
+ return;
+ }
+
+ llvm::outs() << "Found symbol name: " << symbol->name().ToString() << "\n";
+
+ auto sourceInfo{cs.GetSourcePositionRange(symbol->name())};
+ if (!sourceInfo) {
+ llvm_unreachable(
+ "Failed to obtain SourcePosition."
+ "TODO: Please, write a test and replace this with a diagnostic!");
+ return;
+ }
+
+ llvm::outs() << "Found symbol name: " << symbol->name().ToString() << "\n";
+ llvm::outs() << symbol->name().ToString() << ": "
+ << sourceInfo->first.file.path() << ", "
+ << sourceInfo->first.line << ", " << sourceInfo->first.column
+ << "-" << sourceInfo->second.column << "\n";
+}
+
void GetSymbolsSourcesAction::ExecuteAction() {
// Report and exit if fatal semantic errors are present
if (reportFatalSemanticErrors(semantics(), this->instance().diagnostics(),
diff --git a/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index 462de5241f3e6..93bbf4fc9a06f 100644
--- a/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -67,6 +67,9 @@ static std::unique_ptr<FrontendAction> CreateFrontendBaseAction(
case DebugPreFIRTree:
return std::make_unique<DebugPreFIRTreeAction>();
break;
+ case GetDefinition:
+ return std::make_unique<GetDefinitionAction>();
+ break;
case GetSymbolsSources:
return std::make_unique<GetSymbolsSourcesAction>();
break;
diff --git a/flang/test/Driver/driver-help.f90 b/flang/test/Driver/driver-help.f90
index b1b698b99b9bb..9783751a2c9e7 100644
--- a/flang/test/Driver/driver-help.f90
+++ b/flang/test/Driver/driver-help.f90
@@ -91,6 +91,8 @@
! HELP-FC1-NEXT: -ffixed-line-length=<value>
! HELP-FC1-NEXT: Use <value> as character line width in fixed mode
! HELP-FC1-NEXT: -ffree-form Process source files in free form
+! HELP-FC1-NEXT: -fget-definition <value> <value> <value>
+! HELP-FC1-NEXT: Get the symbol definition from <line> <start-column> <end-column>
! HELP-FC1-NEXT: -fget-symbols-sources Dump symbols and their source code locations
! HELP-FC1-NEXT: -fimplicit-none No implicit typing allowed unless overridden by IMPLICIT statements
! HELP-FC1-NEXT: -finput-charset=<value> Specify the default character set for source files
diff --git a/flang/test/Driver/get-definition.f90 b/flang/test/Driver/get-definition.f90
new file mode 100644
index 0000000000000..5e6d5ff2345fe
--- /dev/null
+++ b/flang/test/Driver/get-definition.f90
@@ -0,0 +1,46 @@
+! Verify that the driver correctly rejects invalid values for -fget-definition
+
+!-----------
+! RUN LINES
+!-----------
+! RUN: not %flang_fc1 -fsyntax-only -fget-definition 45 1 2 %s 2>&1 | FileCheck --check-prefix=OK %s
+! RUN: not %flang_fc1 -fsyntax-only -fget-definition a 1 1 %s 2>&1 | FileCheck --check-prefix=ERROR-a %s
+! RUN: not %flang_fc1 -fsyntax-only -fget-definition 1 b 1 %s 2>&1 | FileCheck --check-prefix=ERROR-b %s
+! RUN: not %flang_fc1 -fsyntax-only -fget-definition 1 1 c %s 2>&1 | FileCheck --check-prefix=ERROR-c %s
+! RUN: not %flang_fc1 -fsyntax-only -fget-definition a b 1 %s 2>&1 | FileCheck --check-prefix=ERROR-ab %s
+! RUN: not %flang_fc1 -fsyntax-only -fget-definition a b c %s 2>&1 | FileCheck --check-prefix=ERROR-abc %s
+! RUN: not %flang_fc1 -fsyntax-only -fget-definition 1 b c %s 2>&1 | FileCheck --check-prefix=ERROR-bc %s
+! RUN: not %flang_fc1 -fsyntax-only -fget-definition a 1 c %s 2>&1 | FileCheck --check-prefix=ERROR-ac %s
+
+!-----------------
+! EXPECTED OUTPUT
+!-----------------
+! OK: String range: >m<
+! OK-NOT: error
+
+! ERROR-a: error: invalid value 'a' in 'fget-definition'
+! ERROR-a-NOT: String range: >m<
+
+! ERROR-b: error: invalid value 'b' in 'fget-definition'
+! ERROR-b-NOT: String range: >m<
+
+! ERROR-c: error: invalid value 'c' in 'fget-definition'
+! ERROR-c-NOT: String range: >m<
+
+! ERROR-ab: error: invalid value 'a' in 'fget-definition'
+! ERROR-ab-NOT: String range: >m<
+
+! ERROR-ac: error: invalid value 'a' in 'fget-definition'
+! ERROR-ac-NOT: String range: >m<
+
+! ERROR-bc: error: invalid value 'b' in 'fget-definition'
+! ERROR-bc-NOT: String range: >m<
+
+! ERROR-abc: error: invalid value 'a' in 'fget-definition'
+! ERROR-abc-NOT: String range: >m<
+
+!-------
+! INPUT
+!-------
+module m
+end module
diff --git a/flang/test/Semantics/getdefinition01.f90 b/flang/test/Semantics/getdefinition01.f90
index 06f2cc0f8ddab..b5149e84f6e36 100644
--- a/flang/test/Semantics/getdefinition01.f90
+++ b/flang/test/Semantics/getdefinition01.f90
@@ -16,12 +16,9 @@ recursive pure function f() result(x)
end module
! RUN and CHECK lines at the bottom as this test is sensitive to line numbers
-! RUN: %f18 -fget-definition 6 17 18 -fsyntax-only %s | FileCheck --check-prefix=CHECK1 %s
-! RUN: %f18 -fget-definition 7 20 23 -fsyntax-only %s | FileCheck --check-prefix=CHECK2 %s
-! RUN: %f18 -fget-definition 14 3 4 -fsyntax-only %s | FileCheck --check-prefix=CHECK3 %s
+! RUN: %flang_fc1 -fsyntax-only -fget-definition 6 17 18 %s | FileCheck --check-prefix=CHECK1 %s
+! RUN: %flang_fc1 -fsyntax-only -fget-definition 7 20 23 %s | FileCheck --check-prefix=CHECK2 %s
+! RUN: %flang_fc1 -fsyntax-only -fget-definition 14 3 4 %s | FileCheck --check-prefix=CHECK3 %s
! CHECK1: x:{{.*}}getdefinition01.f90, 5, 21-22
! CHECK2: yyy:{{.*}}getdefinition01.f90, 5, 24-27
! CHECK3: x:{{.*}}getdefinition01.f90, 13, 24-25
-
-! RUN: not %f18 -fget-definition -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK-ERROR %s
-! CHECK-ERROR: Invalid argument to -fget-definitions
diff --git a/flang/test/Semantics/getdefinition02.f b/flang/test/Semantics/getdefinition02.f
index b32536968dc04..29f13ef1b5099 100644
--- a/flang/test/Semantics/getdefinition02.f
+++ b/flang/test/Semantics/getdefinition02.f
@@ -17,9 +17,9 @@ recursive pure function f() result(x)
end module
! RUN and CHECK lines here as test is sensitive to line numbers
-! RUN: %f18 -fget-definition 7 9 10 -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK1 %s
-! RUN: %f18 -fget-definition 8 26 29 -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK2 %s
-! RUN: %f18 -fget-definition 15 9 10 -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK3 %s
+! RUN: %flang_fc1 -fsyntax-only -fget-definition 7 9 10 %s 2>&1 | FileCheck --check-prefix=CHECK1 %s
+! RUN: %flang_fc1 -fsyntax-only -fget-definition 8 26 29 %s 2>&1 | FileCheck --check-prefix=CHECK2 %s
+! RUN: %flang_fc1 -fsyntax-only -fget-definition 15 9 10 %s 2>&1 | FileCheck --check-prefix=CHECK3 %s
! CHECK1: x:{{.*}}getdefinition02.f, 5, 27-28
! CHECK2: yyy:{{.*}}getdefinition02.f, 5, 30-33
! CHECK3: x:{{.*}}getdefinition02.f, 14, 30-31
diff --git a/flang/test/Semantics/getdefinition03-a.f90 b/flang/test/Semantics/getdefinition03-a.f90
index 6e61637b3546b..3c0ba61c1f793 100644
--- a/flang/test/Semantics/getdefinition03-a.f90
+++ b/flang/test/Semantics/getdefinition03-a.f90
@@ -7,7 +7,7 @@ program main
x = f
end program
-! RUN: %f18 -fget-definition 7 6 7 -fsyntax-only %s | FileCheck --check-prefix=CHECK1 %s
-! RUN: %f18 -fget-definition 7 2 3 -fsyntax-only %s | FileCheck --check-prefix=CHECK2 %s
+! RUN: %flang_fc1 -fsyntax-only -fget-definition 7 6 7 %s | FileCheck --check-prefix=CHECK1 %s
+! RUN: %flang_fc1 -fsyntax-only -fget-definition 7 2 3 %s | FileCheck --check-prefix=CHECK2 %s
! CHECK1: f:{{.*}}getdefinition03-b.f90, 2, 12-13
! CHECK2: x:{{.*}}getdefinition03-a.f90, 6, 13-14
diff --git a/flang/test/Semantics/getdefinition04.f90 b/flang/test/Semantics/getdefinition04.f90
index bc01f7979b421..6084f69e7fe1a 100644
--- a/flang/test/Semantics/getdefinition04.f90
+++ b/flang/test/Semantics/getdefinition04.f90
@@ -6,5 +6,5 @@ program main
x = y
end program
-! RUN: %f18 -fget-definition 6 3 4 -fsyntax-only %s | FileCheck %s
+! RUN: %flang_fc1 -fsyntax-only -fget-definition 6 3 4 %s | FileCheck %s
! CHECK: x:{{.*}}getdefinition04.f90, 3, 14-15
diff --git a/flang/test/Semantics/getdefinition05.f90 b/flang/test/Semantics/getdefinition05.f90
index 91952bb7fcc33..74e3d71b6a279 100644
--- a/flang/test/Semantics/getdefinition05.f90
+++ b/flang/test/Semantics/getdefinition05.f90
@@ -12,8 +12,8 @@ program main
end program
!! Inner x
-! RUN: %f18 -fget-definition 9 5 6 -fsyntax-only %s | FileCheck --check-prefix=CHECK1 %s
+! RUN: %flang_fc1 -fsyntax-only -fget-definition 9 5 6 %s | FileCheck --check-prefix=CHECK1 %s
! CHECK1: x:{{.*}}getdefinition05.f90, 7, 16-17
!! Outer y
-! RUN: %f18 -fget-definition 11 7 8 -fsyntax-only %s | FileCheck --check-prefix=CHECK2 %s
+! RUN: %flang_fc1 -fsyntax-only -fget-definition 11 7 8 %s | FileCheck --check-prefix=CHECK2 %s
! CHECK2: y:{{.*}}getdefinition05.f90, 5, 14-15
diff --git a/flang/tools/f18/f18.cpp b/flang/tools/f18/f18.cpp
index 1a658781d263b..691d4378928a3 100644
--- a/flang/tools/f18/f18.cpp
+++ b/flang/tools/f18/f18.cpp
@@ -658,8 +658,8 @@ int main(int argc, char *const argv[]) {
}
arguments[i] = std::strtol(args.front().c_str(), &endptr, 10);
if (*endptr != '\0') {
- llvm::errs() << "Invalid argument to -fget-definitions: "
- << args.front() << '\n';
+ llvm::errs() << "error: invalid value '" << args.front()
+ << "' in 'fget-definition'" << '\n';
return EXIT_FAILURE;
}
args.pop_front();
More information about the cfe-commits
mailing list