Bug Summary

File:build/source/flang/tools/f18-parse-demo/f18-parse-demo.cpp
Warning:line 167, column 8
Value stored to 'start' during its initialization is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name f18-parse-demo.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=none -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/source/build-llvm/tools/clang/stage2-bins -resource-dir /usr/lib/llvm-17/lib/clang/17 -isystem /build/source/llvm/../mlir/include -isystem tools/mlir/include -isystem tools/clang/include -isystem /build/source/llvm/../clang/include -D FLANG_INCLUDE_TESTS=1 -D FLANG_LITTLE_ENDIAN=1 -D FLANG_VENDOR="Debian " -D _DEBUG -D _GLIBCXX_ASSERTIONS -D _GNU_SOURCE -D _LIBCPP_ENABLE_ASSERTIONS -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I tools/flang/tools/f18-parse-demo -I /build/source/flang/tools/f18-parse-demo -I /build/source/flang/include -I tools/flang/include -I include -I /build/source/llvm/include -D _FORTIFY_SOURCE=2 -D NDEBUG -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -internal-isystem /usr/lib/llvm-17/lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fmacro-prefix-map=/build/source/= -fcoverage-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fcoverage-prefix-map=/build/source/= -source-date-epoch 1683717183 -O2 -Wno-unused-command-line-argument -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wno-comment -Wno-misleading-indentation -Wno-deprecated-copy -Wno-ctad-maybe-unsupported -std=c++17 -fdeprecated-macro -fdebug-compilation-dir=/build/source/build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/source/= -ferror-limit 19 -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2023-05-10-133810-16478-1 -x c++ /build/source/flang/tools/f18-parse-demo/f18-parse-demo.cpp
1//===-- tools/f18/f18-parse-demo.cpp --------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9// F18 parsing demonstration.
10// f18-parse-demo [ -E | -fdump-parse-tree | -funparse-only ]
11// foo.{f,F,f77,F77,f90,F90,&c.}
12//
13// By default, runs the supplied source files through the F18 preprocessing and
14// parsing phases, reconstitutes a Fortran program from the parse tree, and
15// passes that Fortran program to a Fortran compiler identified by the $F18_FC
16// environment variable (defaulting to gfortran). The Fortran preprocessor is
17// always run, whatever the case of the source file extension. Unrecognized
18// options are passed through to the underlying Fortran compiler.
19//
20// This program is actually a stripped-down variant of f18.cpp, a temporary
21// scaffolding compiler driver that can test some semantic passes of the
22// F18 compiler under development.
23
24#include "flang/Common/Fortran-features.h"
25#include "flang/Common/default-kinds.h"
26#include "flang/Parser/characters.h"
27#include "flang/Parser/dump-parse-tree.h"
28#include "flang/Parser/message.h"
29#include "flang/Parser/parse-tree-visitor.h"
30#include "flang/Parser/parse-tree.h"
31#include "flang/Parser/parsing.h"
32#include "flang/Parser/provenance.h"
33#include "flang/Parser/unparse.h"
34#include "llvm/Support/Errno.h"
35#include "llvm/Support/FileSystem.h"
36#include "llvm/Support/Program.h"
37#include "llvm/Support/raw_ostream.h"
38#include <cstdio>
39#include <cstring>
40#include <fstream>
41#include <list>
42#include <memory>
43#include <optional>
44#include <stdlib.h>
45#include <string>
46#include <time.h>
47#include <vector>
48
49static std::list<std::string> argList(int argc, char *const argv[]) {
50 std::list<std::string> result;
51 for (int j = 0; j < argc; ++j) {
52 result.emplace_back(argv[j]);
53 }
54 return result;
55}
56
57std::vector<std::string> filesToDelete;
58
59void CleanUpAtExit() {
60 for (const auto &path : filesToDelete) {
61 if (!path.empty()) {
62 llvm::sys::fs::remove(path);
63 }
64 }
65}
66
67#if _POSIX_C_SOURCE200809L >= 199309L && _POSIX_TIMERS > 0 && _POSIX_CPUTIME && \
68 defined CLOCK_PROCESS_CPUTIME_ID2
69static constexpr bool canTime{true};
70double CPUseconds() {
71 struct timespec tspec;
72 clock_gettime(CLOCK_PROCESS_CPUTIME_ID2, &tspec);
73 return tspec.tv_nsec * 1.0e-9 + tspec.tv_sec;
74}
75#else
76static constexpr bool canTime{false};
77double CPUseconds() { return 0; }
78#endif
79
80struct DriverOptions {
81 DriverOptions() {}
82 bool verbose{false}; // -v
83 bool compileOnly{false}; // -c
84 std::string outputPath; // -o path
85 std::vector<std::string> searchDirectories{"."s}; // -I dir
86 bool forcedForm{false}; // -Mfixed or -Mfree appeared
87 bool warnOnNonstandardUsage{false}; // -Mstandard
88 bool warningsAreErrors{false}; // -Werror
89 Fortran::parser::Encoding encoding{Fortran::parser::Encoding::LATIN_1};
90 bool lineDirectives{true}; // -P disables
91 bool syntaxOnly{false};
92 bool dumpProvenance{false};
93 bool noReformat{false}; // -E -fno-reformat
94 bool dumpUnparse{false};
95 bool dumpParseTree{false};
96 bool timeParse{false};
97 std::vector<std::string> fcArgs;
98 const char *prefix{nullptr};
99};
100
101void Exec(std::vector<llvm::StringRef> &argv, bool verbose = false) {
102 if (verbose) {
103 for (size_t j{0}; j < argv.size(); ++j) {
104 llvm::errs() << (j > 0 ? " " : "") << argv[j];
105 }
106 llvm::errs() << '\n';
107 }
108 std::string ErrMsg;
109 llvm::ErrorOr<std::string> Program = llvm::sys::findProgramByName(argv[0]);
110 if (!Program)
111 ErrMsg = Program.getError().message();
112 if (!Program ||
113 llvm::sys::ExecuteAndWait(
114 Program.get(), argv, std::nullopt, {}, 0, 0, &ErrMsg)) {
115 llvm::errs() << "execvp(" << argv[0] << ") failed: " << ErrMsg << '\n';
116 exit(EXIT_FAILURE1);
117 }
118}
119
120void RunOtherCompiler(DriverOptions &driver, char *source, char *relo) {
121 std::vector<llvm::StringRef> argv;
122 for (size_t j{0}; j < driver.fcArgs.size(); ++j) {
123 argv.push_back(driver.fcArgs[j]);
124 }
125 char dashC[3] = "-c", dashO[3] = "-o";
126 argv.push_back(dashC);
127 argv.push_back(dashO);
128 argv.push_back(relo);
129 argv.push_back(source);
130 Exec(argv, driver.verbose);
131}
132
133std::string RelocatableName(const DriverOptions &driver, std::string path) {
134 if (driver.compileOnly && !driver.outputPath.empty()) {
135 return driver.outputPath;
136 }
137 std::string base{path};
138 auto slash{base.rfind("/")};
139 if (slash != std::string::npos) {
140 base = base.substr(slash + 1);
141 }
142 std::string relo{base};
143 auto dot{base.rfind(".")};
144 if (dot != std::string::npos) {
145 relo = base.substr(0, dot);
146 }
147 relo += ".o";
148 return relo;
149}
150
151int exitStatus{EXIT_SUCCESS0};
152
153std::string CompileFortran(
154 std::string path, Fortran::parser::Options options, DriverOptions &driver) {
155 if (!driver.forcedForm) {
156 auto dot{path.rfind(".")};
157 if (dot != std::string::npos) {
158 std::string suffix{path.substr(dot + 1)};
159 options.isFixedForm = suffix == "f" || suffix == "F" || suffix == "ff";
160 }
161 }
162 options.searchDirectories = driver.searchDirectories;
163 Fortran::parser::AllSources allSources;
164 Fortran::parser::AllCookedSources allCookedSources{allSources};
165 Fortran::parser::Parsing parsing{allCookedSources};
166
167 auto start{CPUseconds()};
Value stored to 'start' during its initialization is never read
168 parsing.Prescan(path, options);
169 if (!parsing.messages().empty() &&
170 (driver.warningsAreErrors || parsing.messages().AnyFatalError())) {
171 llvm::errs() << driver.prefix << "could not scan " << path << '\n';
172 parsing.messages().Emit(llvm::errs(), parsing.allCooked());
173 exitStatus = EXIT_FAILURE1;
174 return {};
175 }
176 if (driver.dumpProvenance) {
177 parsing.DumpProvenance(llvm::outs());
178 return {};
179 }
180 if (options.prescanAndReformat) {
181 parsing.messages().Emit(llvm::errs(), allCookedSources);
182 if (driver.noReformat) {
183 parsing.DumpCookedChars(llvm::outs());
184 } else {
185 parsing.EmitPreprocessedSource(llvm::outs(), driver.lineDirectives);
186 }
187 return {};
188 }
189 parsing.Parse(llvm::outs());
190 auto stop{CPUseconds()};
191 if (driver.timeParse) {
192 if (canTime) {
193 llvm::outs() << "parse time for " << path << ": " << (stop - start)
194 << " CPU seconds\n";
195 } else {
196 llvm::outs() << "no timing information due to lack of clock_gettime()\n";
197 }
198 }
199
200 parsing.ClearLog();
201 parsing.messages().Emit(llvm::errs(), parsing.allCooked());
202 if (!parsing.consumedWholeFile()) {
203 parsing.EmitMessage(llvm::errs(), parsing.finalRestingPlace(),
204 "parser FAIL (final position)", "error: ", llvm::raw_ostream::RED);
205 exitStatus = EXIT_FAILURE1;
206 return {};
207 }
208 if ((!parsing.messages().empty() &&
209 (driver.warningsAreErrors || parsing.messages().AnyFatalError())) ||
210 !parsing.parseTree()) {
211 llvm::errs() << driver.prefix << "could not parse " << path << '\n';
212 exitStatus = EXIT_FAILURE1;
213 return {};
214 }
215 auto &parseTree{*parsing.parseTree()};
216 if (driver.dumpParseTree) {
217 Fortran::parser::DumpTree(llvm::outs(), parseTree);
218 return {};
219 }
220 if (driver.dumpUnparse) {
221 Unparse(llvm::outs(), parseTree, driver.encoding, true /*capitalize*/,
222 options.features.IsEnabled(
223 Fortran::common::LanguageFeature::BackslashEscapes));
224 return {};
225 }
226 if (driver.syntaxOnly) {
227 return {};
228 }
229
230 std::string relo{RelocatableName(driver, path)};
231
232 llvm::SmallString<32> tmpSourcePath;
233 {
234 int fd;
235 std::error_code EC =
236 llvm::sys::fs::createUniqueFile("f18-%%%%.f90", fd, tmpSourcePath);
237 if (EC) {
238 llvm::errs() << EC.message() << "\n";
239 std::exit(EXIT_FAILURE1);
240 }
241 llvm::raw_fd_ostream tmpSource(fd, /*shouldClose*/ true);
242 Unparse(tmpSource, parseTree, driver.encoding, true /*capitalize*/,
243 options.features.IsEnabled(
244 Fortran::common::LanguageFeature::BackslashEscapes));
245 }
246
247 RunOtherCompiler(driver, tmpSourcePath.data(), relo.data());
248 filesToDelete.emplace_back(tmpSourcePath);
249 if (!driver.compileOnly && driver.outputPath.empty()) {
250 filesToDelete.push_back(relo);
251 }
252 return relo;
253}
254
255std::string CompileOtherLanguage(std::string path, DriverOptions &driver) {
256 std::string relo{RelocatableName(driver, path)};
257 RunOtherCompiler(driver, path.data(), relo.data());
258 if (!driver.compileOnly && driver.outputPath.empty()) {
259 filesToDelete.push_back(relo);
260 }
261 return relo;
262}
263
264void Link(std::vector<std::string> &relocatables, DriverOptions &driver) {
265 std::vector<llvm::StringRef> argv;
266 for (size_t j{0}; j < driver.fcArgs.size(); ++j) {
267 argv.push_back(driver.fcArgs[j].data());
268 }
269 for (auto &relo : relocatables) {
270 argv.push_back(relo.data());
271 }
272 if (!driver.outputPath.empty()) {
273 char dashO[3] = "-o";
274 argv.push_back(dashO);
275 argv.push_back(driver.outputPath.data());
276 }
277 Exec(argv, driver.verbose);
278}
279
280int main(int argc, char *const argv[]) {
281
282 atexit(CleanUpAtExit);
283
284 DriverOptions driver;
285 const char *fc{getenv("F18_FC")};
286 driver.fcArgs.push_back(fc ? fc : "gfortran");
287
288 std::list<std::string> args{argList(argc, argv)};
289 std::string prefix{args.front()};
290 args.pop_front();
291 prefix += ": ";
292 driver.prefix = prefix.data();
293
294 Fortran::parser::Options options;
295 options.predefinitions.emplace_back("__F18", "1");
296 options.predefinitions.emplace_back("__F18_MAJOR__", "1");
297 options.predefinitions.emplace_back("__F18_MINOR__", "1");
298 options.predefinitions.emplace_back("__F18_PATCHLEVEL__", "1");
299
300 options.features.Enable(
301 Fortran::common::LanguageFeature::BackslashEscapes, true);
302
303 Fortran::common::IntrinsicTypeDefaultKinds defaultKinds;
304
305 std::vector<std::string> fortranSources, otherSources, relocatables;
306 bool anyFiles{false};
307
308 while (!args.empty()) {
309 std::string arg{std::move(args.front())};
310 args.pop_front();
311 if (arg.empty() || arg == "-Xflang") {
312 } else if (arg.at(0) != '-') {
313 anyFiles = true;
314 auto dot{arg.rfind(".")};
315 if (dot == std::string::npos) {
316 driver.fcArgs.push_back(arg);
317 } else {
318 std::string suffix{arg.substr(dot + 1)};
319 if (suffix == "f" || suffix == "F" || suffix == "ff" ||
320 suffix == "f90" || suffix == "F90" || suffix == "ff90" ||
321 suffix == "f95" || suffix == "F95" || suffix == "ff95" ||
322 suffix == "cuf" || suffix == "CUF" || suffix == "f18" ||
323 suffix == "F18" || suffix == "ff18") {
324 fortranSources.push_back(arg);
325 } else if (suffix == "o" || suffix == "a") {
326 relocatables.push_back(arg);
327 } else {
328 otherSources.push_back(arg);
329 }
330 }
331 } else if (arg == "-") {
332 fortranSources.push_back("-");
333 } else if (arg == "--") {
334 while (!args.empty()) {
335 fortranSources.emplace_back(std::move(args.front()));
336 args.pop_front();
337 }
338 break;
339 } else if (arg == "-Mfixed") {
340 driver.forcedForm = true;
341 options.isFixedForm = true;
342 } else if (arg == "-Mfree") {
343 driver.forcedForm = true;
344 options.isFixedForm = false;
345 } else if (arg == "-Mextend") {
346 options.fixedFormColumns = 132;
347 } else if (arg == "-Mbackslash") {
348 options.features.Enable(
349 Fortran::common::LanguageFeature::BackslashEscapes, false);
350 } else if (arg == "-Mnobackslash") {
351 options.features.Enable(
352 Fortran::common::LanguageFeature::BackslashEscapes);
353 } else if (arg == "-Mstandard") {
354 driver.warnOnNonstandardUsage = true;
355 } else if (arg == "-fopenmp") {
356 options.features.Enable(Fortran::common::LanguageFeature::OpenMP);
357 options.predefinitions.emplace_back("_OPENMP", "201511");
358 } else if (arg == "-Werror") {
359 driver.warningsAreErrors = true;
360 } else if (arg == "-ed") {
361 options.features.Enable(Fortran::common::LanguageFeature::OldDebugLines);
362 } else if (arg == "-E") {
363 options.prescanAndReformat = true;
364 } else if (arg == "-P") {
365 driver.lineDirectives = false;
366 } else if (arg == "-fno-reformat") {
367 driver.noReformat = true;
368 } else if (arg == "-fbackslash") {
369 options.features.Enable(
370 Fortran::common::LanguageFeature::BackslashEscapes);
371 } else if (arg == "-fno-backslash") {
372 options.features.Enable(
373 Fortran::common::LanguageFeature::BackslashEscapes, false);
374 } else if (arg == "-fdump-provenance") {
375 driver.dumpProvenance = true;
376 } else if (arg == "-fdump-parse-tree") {
377 driver.dumpParseTree = true;
378 } else if (arg == "-funparse") {
379 driver.dumpUnparse = true;
380 } else if (arg == "-ftime-parse") {
381 driver.timeParse = true;
382 } else if (arg == "-fparse-only" || arg == "-fsyntax-only") {
383 driver.syntaxOnly = true;
384 } else if (arg == "-c") {
385 driver.compileOnly = true;
386 } else if (arg == "-o") {
387 driver.outputPath = args.front();
388 args.pop_front();
389 } else if (arg.substr(0, 2) == "-D") {
390 auto eq{arg.find('=')};
391 if (eq == std::string::npos) {
392 options.predefinitions.emplace_back(arg.substr(2), "1");
393 } else {
394 options.predefinitions.emplace_back(
395 arg.substr(2, eq - 2), arg.substr(eq + 1));
396 }
397 } else if (arg.substr(0, 2) == "-U") {
398 options.predefinitions.emplace_back(
399 arg.substr(2), std::optional<std::string>{});
400 } else if (arg == "-r8" || arg == "-fdefault-real-8") {
401 defaultKinds.set_defaultRealKind(8);
402 } else if (arg == "-i8" || arg == "-fdefault-integer-8") {
403 defaultKinds.set_defaultIntegerKind(8);
404 } else if (arg == "-help" || arg == "--help" || arg == "-?") {
405 llvm::errs()
406 << "f18-parse-demo options:\n"
407 << " -Mfixed | -Mfree force the source form\n"
408 << " -Mextend 132-column fixed form\n"
409 << " -f[no-]backslash enable[disable] \\escapes in literals\n"
410 << " -M[no]backslash disable[enable] \\escapes in literals\n"
411 << " -Mstandard enable conformance warnings\n"
412 << " -r8 | -fdefault-real-8 | -i8 | -fdefault-integer-8 "
413 "change default kinds of intrinsic types\n"
414 << " -Werror treat warnings as errors\n"
415 << " -ed enable fixed form D lines\n"
416 << " -E prescan & preprocess only\n"
417 << " -ftime-parse measure parsing time\n"
418 << " -fsyntax-only parse only, no output except messages\n"
419 << " -funparse parse & reformat only, no code "
420 "generation\n"
421 << " -fdump-provenance dump the provenance table (no code)\n"
422 << " -fdump-parse-tree dump the parse tree (no code)\n"
423 << " -v -c -o -I -D -U have their usual meanings\n"
424 << " -help print this again\n"
425 << "Other options are passed through to the $F18_FC compiler.\n";
426 return exitStatus;
427 } else if (arg == "-V") {
428 llvm::errs() << "\nf18-parse-demo\n";
429 return exitStatus;
430 } else {
431 driver.fcArgs.push_back(arg);
432 if (arg == "-v") {
433 driver.verbose = true;
434 } else if (arg == "-I") {
435 driver.fcArgs.push_back(args.front());
436 driver.searchDirectories.push_back(args.front());
437 args.pop_front();
438 } else if (arg.substr(0, 2) == "-I") {
439 driver.searchDirectories.push_back(arg.substr(2));
440 }
441 }
442 }
443
444 if (driver.warnOnNonstandardUsage) {
445 options.features.WarnOnAllNonstandard();
446 }
447 if (!options.features.IsEnabled(
448 Fortran::common::LanguageFeature::BackslashEscapes)) {
449 driver.fcArgs.push_back("-fno-backslash"); // PGI "-Mbackslash"
450 }
451
452 if (!anyFiles) {
453 driver.dumpUnparse = true;
454 CompileFortran("-", options, driver);
455 return exitStatus;
456 }
457 for (const auto &path : fortranSources) {
458 std::string relo{CompileFortran(path, options, driver)};
459 if (!driver.compileOnly && !relo.empty()) {
460 relocatables.push_back(relo);
461 }
462 }
463 for (const auto &path : otherSources) {
464 std::string relo{CompileOtherLanguage(path, driver)};
465 if (!driver.compileOnly && !relo.empty()) {
466 relocatables.push_back(relo);
467 }
468 }
469 if (!relocatables.empty()) {
470 Link(relocatables, driver);
471 }
472 return exitStatus;
473}