FLANG
semantics.h
1//===-- include/flang/Semantics/semantics.h ---------------------*- C++ -*-===//
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#ifndef FORTRAN_SEMANTICS_SEMANTICS_H_
10#define FORTRAN_SEMANTICS_SEMANTICS_H_
11
12#include "module-dependences.h"
13#include "program-tree.h"
14#include "scope.h"
15#include "symbol.h"
16#include "flang/Evaluate/common.h"
17#include "flang/Evaluate/intrinsics.h"
18#include "flang/Evaluate/target.h"
19#include "flang/Parser/message.h"
20#include "flang/Support/Fortran-features.h"
21#include "flang/Support/LangOptions.h"
22#include <set>
23#include <string>
24#include <vector>
25
26namespace llvm {
27class raw_ostream;
28}
29
30namespace Fortran::common {
32}
33
34namespace Fortran::parser {
35struct AccObject;
36struct Name;
37struct Program;
40struct BlockConstruct;
41struct CaseConstruct;
42struct DoConstruct;
45struct ForallConstruct;
46struct IfConstruct;
49struct Variable;
50struct WhereConstruct;
51} // namespace Fortran::parser
52
53namespace Fortran::semantics {
54
55class Symbol;
56class CommonBlockMap;
57using CommonBlockList = std::vector<std::pair<SymbolRef, std::size_t>>;
58
59using ConstructNode = std::variant<const parser::AssociateConstruct *,
60 const parser::BlockConstruct *, const parser::CaseConstruct *,
61 const parser::ChangeTeamConstruct *, const parser::CriticalConstruct *,
62 const parser::DoConstruct *, const parser::ForallConstruct *,
63 const parser::IfConstruct *, const parser::SelectRankConstruct *,
64 const parser::SelectTypeConstruct *, const parser::WhereConstruct *>;
65using ConstructStack = std::vector<ConstructNode>;
66
67class SemanticsContext {
68public:
69 SemanticsContext(const common::IntrinsicTypeDefaultKinds &,
72 common::FPMaxminBehavior = common::FPMaxminBehavior::Legacy);
73 ~SemanticsContext();
74
75 const common::IntrinsicTypeDefaultKinds &defaultKinds() const {
76 return defaultKinds_;
77 }
78 const common::LanguageFeatureControl &languageFeatures() const {
79 return languageFeatures_;
80 }
81 const common::LangOptions &langOptions() const { return langOpts_; }
82 const std::string &openAccDefaultNoneScalarsStrictDisableOption() const {
83 return openAccDefaultNoneScalarsStrictDisableOption_;
84 }
85 int GetDefaultKind(TypeCategory) const;
86 int doublePrecisionKind() const {
87 return defaultKinds_.doublePrecisionKind();
88 }
89 int quadPrecisionKind() const { return defaultKinds_.quadPrecisionKind(); }
90 bool IsEnabled(common::LanguageFeature feature) const {
91 return languageFeatures_.IsEnabled(feature);
92 }
93 template <typename A> bool ShouldWarn(A x) const {
94 return languageFeatures_.ShouldWarn(x);
95 }
96 const std::optional<parser::CharBlock> &location() const { return location_; }
97 const std::vector<std::string> &searchDirectories() const {
98 return searchDirectories_;
99 }
100 const std::vector<std::string> &intrinsicModuleDirectories() const {
101 return intrinsicModuleDirectories_;
102 }
103 const std::vector<std::string> &implicitUseModules() const {
104 return implicitUseModules_;
105 }
106 const std::string &moduleDirectory() const { return moduleDirectory_; }
107 const std::string &moduleFileSuffix() const { return moduleFileSuffix_; }
108 bool underscoring() const { return underscoring_; }
109 bool warningsAreErrors() const { return warningsAreErrors_; }
110 bool debugModuleWriter() const { return debugModuleWriter_; }
111 const evaluate::IntrinsicProcTable &intrinsics() const { return intrinsics_; }
112 const evaluate::TargetCharacteristics &targetCharacteristics() const {
113 return targetCharacteristics_;
114 }
115 evaluate::TargetCharacteristics &targetCharacteristics() {
116 return targetCharacteristics_;
117 }
118 const std::string &targetTriple() const { return targetTriple_; }
119 const std::string &targetFeatures() const { return targetFeatures_; }
120 Scope &globalScope() { return globalScope_; }
121 Scope &intrinsicModulesScope() { return intrinsicModulesScope_; }
122 Scope *currentHermeticModuleFileScope() {
123 return currentHermeticModuleFileScope_;
124 }
125 void set_currentHermeticModuleFileScope(Scope *scope) {
126 currentHermeticModuleFileScope_ = scope;
127 }
128 parser::Messages &messages() { return messages_; }
129 evaluate::FoldingContext &foldingContext() { return foldingContext_; }
130 parser::AllCookedSources &allCookedSources() { return allCookedSources_; }
131 ModuleDependences &moduleDependences() { return moduleDependences_; }
132 std::map<const Symbol *, SourceName> &moduleFileOutputRenamings() {
133 return moduleFileOutputRenamings_;
134 }
135
136 SemanticsContext &set_location(
137 const std::optional<parser::CharBlock> &location) {
138 location_ = location;
139 return *this;
140 }
141 SemanticsContext &set_searchDirectories(const std::vector<std::string> &x) {
142 searchDirectories_ = x;
143 return *this;
144 }
145 SemanticsContext &set_intrinsicModuleDirectories(
146 const std::vector<std::string> &x) {
147 intrinsicModuleDirectories_ = x;
148 return *this;
149 }
150 SemanticsContext &set_implicitUseModules(const std::vector<std::string> &x) {
151 implicitUseModules_ = x;
152 return *this;
153 }
154 SemanticsContext &set_moduleDirectory(const std::string &x) {
155 moduleDirectory_ = x;
156 return *this;
157 }
158 SemanticsContext &set_moduleFileSuffix(const std::string &x) {
159 moduleFileSuffix_ = x;
160 return *this;
161 }
162 SemanticsContext &set_underscoring(bool x) {
163 underscoring_ = x;
164 return *this;
165 }
166 SemanticsContext &set_warnOnNonstandardUsage(bool x) {
167 warnOnNonstandardUsage_ = x;
168 return *this;
169 }
170 SemanticsContext &set_maxErrors(size_t x) {
171 maxErrors_ = x;
172 return *this;
173 }
174 SemanticsContext &set_warningsAreErrors(bool x) {
175 warningsAreErrors_ = x;
176 return *this;
177 }
178 SemanticsContext &set_debugModuleWriter(bool x) {
179 debugModuleWriter_ = x;
180 return *this;
181 }
182 SemanticsContext &set_openAccDefaultNoneScalarsStrictDisableOption(
183 std::string x) {
184 openAccDefaultNoneScalarsStrictDisableOption_ = std::move(x);
185 return *this;
186 }
187 SemanticsContext &set_targetTriple(const std::string &x) {
188 targetTriple_ = x;
189 return *this;
190 }
191 SemanticsContext &set_targetFeatures(const std::string &x) {
192 targetFeatures_ = x;
193 return *this;
194 }
195
196 const DeclTypeSpec &MakeNumericType(TypeCategory, int kind = 0);
197 const DeclTypeSpec &MakeLogicalType(int kind = 0);
198
199 std::size_t maxErrors() const { return maxErrors_; }
200
201 bool AnyFatalError() const;
202
203 // Test or set the Error flag on a Symbol
204 bool HasError(const Symbol &);
205 bool HasError(const Symbol *);
206 bool HasError(const parser::Name &);
207 void SetError(const Symbol &, bool = true);
208
209 template <typename... A> parser::Message &Say(A &&...args) {
210 CHECK(location_);
211 return messages_.Say(*location_, std::forward<A>(args)...);
212 }
213 template <typename... A>
214 parser::Message &Say(parser::CharBlock at, A &&...args) {
215 return messages_.Say(at, std::forward<A>(args)...);
216 }
217 parser::Message &Say(parser::Message &&msg) {
218 return messages_.Say(std::move(msg));
219 }
220 template <typename... A>
221 parser::Message &SayWithDecl(const Symbol &symbol,
223 A &&...args) {
224 auto &message{Say(at, std::move(msg), args...)};
225 evaluate::AttachDeclaration(&message, symbol);
226 return message;
227 }
228
229 template <typename... A>
230 parser::Message *Warn(parser::Messages &messages,
231 common::LanguageFeature feature, parser::CharBlock at, A &&...args) {
232 return messages.Warn(IsInModuleFile(at), languageFeatures_, feature, at,
233 std::forward<A>(args)...);
234 }
235 template <typename... A>
236 parser::Message *Warn(parser::Messages &messages,
237 common::UsageWarning warning, parser::CharBlock at, A &&...args) {
238 return messages.Warn(IsInModuleFile(at), languageFeatures_, warning, at,
239 std::forward<A>(args)...);
240 }
241 template <typename... A>
243 common::LanguageFeature feature, parser::CharBlock at, A &&...args) {
244 return messages.Warn(IsInModuleFile(at), languageFeatures_, feature, at,
245 std::forward<A>(args)...);
246 }
247 template <typename... A>
249 common::UsageWarning warning, parser::CharBlock at, A &&...args) {
250 return messages.Warn(IsInModuleFile(at), languageFeatures_, warning, at,
251 std::forward<A>(args)...);
252 }
253 template <typename... A>
255 common::LanguageFeature feature, A &&...args) {
256 return messages.Warn(IsInModuleFile(messages.at()), languageFeatures_,
257 feature, messages.at(), std::forward<A>(args)...);
258 }
259 template <typename... A>
261 common::UsageWarning warning, A &&...args) {
262 return messages.Warn(IsInModuleFile(messages.at()), languageFeatures_,
263 warning, messages.at(), std::forward<A>(args)...);
264 }
265 template <typename... A>
266 parser::Message *Warn(
267 common::LanguageFeature feature, parser::CharBlock at, A &&...args) {
268 return Warn(messages_, feature, at, std::forward<A>(args)...);
269 }
270 template <typename... A>
271 parser::Message *Warn(
272 common::UsageWarning warning, parser::CharBlock at, A &&...args) {
273 return Warn(messages_, warning, at, std::forward<A>(args)...);
274 }
275 template <typename... A>
276 parser::Message *Warn(common::LanguageFeature feature, A &&...args) {
277 CHECK(location_);
278 return Warn(feature, *location_, std::forward<A>(args)...);
279 }
280 template <typename... A>
281 parser::Message *Warn(common::UsageWarning warning, A &&...args) {
282 CHECK(location_);
283 return Warn(warning, *location_, std::forward<A>(args)...);
284 }
285
286 void EmitMessages(llvm::raw_ostream &);
287
288 const Scope &FindScope(parser::CharBlock) const;
289 Scope &FindScope(parser::CharBlock);
290 void UpdateScopeIndex(Scope &, parser::CharBlock);
291 void DumpScopeIndex(llvm::raw_ostream &) const;
292
293 bool IsInModuleFile(parser::CharBlock) const;
294
295 const ConstructStack &constructStack() const { return constructStack_; }
296 template <typename N> void PushConstruct(const N &node) {
297 constructStack_.emplace_back(&node);
298 }
299 void PopConstruct();
300
301 ENUM_CLASS(IndexVarKind, DO, FORALL)
302 // Check to see if a variable being redefined is a DO or FORALL index.
303 // If so, emit a message.
304 void WarnIndexVarRedefine(const parser::CharBlock &, const Symbol &);
305 void CheckIndexVarRedefine(const parser::CharBlock &, const Symbol &);
306 void CheckIndexVarRedefine(const parser::Variable &);
307 void CheckIndexVarRedefine(const parser::Name &);
308 void ActivateIndexVar(const parser::Name &, IndexVarKind);
309 void DeactivateIndexVar(const parser::Name &);
310 SymbolVector GetIndexVars(IndexVarKind);
311 SourceName SaveTempName(std::string &&);
312 SourceName GetTempName(const Scope &);
313 static bool IsTempName(const std::string &);
314
315 // Locate and process the contents of a built-in module on demand
316 Scope *GetBuiltinModule(const char *name);
317
318 // Defines builtinsScope_ from the __Fortran_builtins module
319 void UseFortranBuiltinsModule();
320 const Scope *GetBuiltinsScope() const { return builtinsScope_; }
321
322 // Locate CUDA intrinsic modules on demand. These return null after emitting a
323 // diagnostic when the required module file cannot be read.
324 const Scope *GetCUDABuiltinsScope();
325 const Scope *GetCUDADeviceScope();
326
327 void UsePPCBuiltinTypesModule();
328 void UsePPCBuiltinsModule();
329 Scope *GetPPCBuiltinTypesScope() { return ppcBuiltinTypesScope_; }
330 const Scope *GetPPCBuiltinsScope() const { return ppcBuiltinsScope_; }
331
332 // Saves a module file's parse tree so that it remains available
333 // during semantics.
334 parser::Program &SaveParseTree(parser::Program &&);
335
336 // Ensures a common block definition does not conflict with previous
337 // appearances in the program and consolidate information about
338 // common blocks at the program level for later checks and lowering.
339 // This can obviously not check any conflicts between different compilation
340 // units (in case such conflicts exist, the behavior will depend on the
341 // linker).
342 void MapCommonBlockAndCheckConflicts(const Symbol &);
343
344 // After DATA statement initializations have been compiled into
345 // symbol initializer values, check any pending conflicts recorded by
346 // MapCommonBlockAndCheckConflicts() that could not be resolved earlier
347 // because the initializer values were not yet known: a duplicate
348 // initialization (identical values) of a COMMON block appearing in more
349 // than one program unit is accepted as an extension, but a conflicting
350 // one is a hard error.
351 void CheckCommonBlockInitializationConflicts();
352
353 // Get the list of common blocks appearing in the program. If a common block
354 // appears in several subprograms, only one of its appearance is returned in
355 // the list alongside the biggest byte size of all its appearances.
356 // If a common block is initialized in any of its appearances, the list will
357 // contain the appearance with the initialization, otherwise the appearance
358 // with the biggest size is returned. The extra byte size information allows
359 // handling the case where the common block initialization is not the
360 // appearance with the biggest size: the common block will have the biggest
361 // size with the first bytes initialized with the initial value. This is not
362 // standard, if the initialization and biggest size appearances are in
363 // different compilation units, the behavior will depend on the linker. The
364 // linker may have the behavior described before, but it may also keep the
365 // initialized common symbol without extending its size, or have some other
366 // behavior.
367 CommonBlockList GetCommonBlocks() const;
368
369 void NoteDefinedSymbol(const Symbol &);
370 bool IsSymbolDefined(const Symbol &) const;
371 void NoteUsedSymbol(const Symbol &);
372 void NoteUsedSymbols(const UnorderedSymbolSet &);
373 bool IsSymbolUsed(const Symbol &) const;
374
375 // Track same-kind duplicate AccObjects between resolve-directives and
376 // rewrite-parse-tree (e.g. the second `x` in `private(x, x)`).
377 void MarkAccObjectDuplicate(const parser::AccObject *o) {
378 accObjectDuplicates_.insert(o);
379 }
380 bool IsAccObjectDuplicate(const parser::AccObject *o) const {
381 return accObjectDuplicates_.count(o) != 0;
382 }
383
384 void DumpSymbols(llvm::raw_ostream &);
385
386 // Top-level ProgramTrees are owned by the SemanticsContext for persistence.
387 ProgramTree &SaveProgramTree(ProgramTree &&);
388
389 const std::list<parser::Program> &GetModFileParseTrees() {
390 return modFileParseTrees_;
391 }
392
393 // Label analysis classifies every labeled statement, and only some of those
394 // classifications may be named by a statement that branches. Lowering needs
395 // the same distinction when it records the targets of a branch, so the
396 // positions of the statements that may be branched to are kept here rather
397 // than being derived a second time from the parse tree.
398 void RecordBranchTarget(parser::CharBlock statementPosition) {
399 branchTargets_.insert(statementPosition);
400 }
401
402 bool IsRecordedBranchTarget(parser::CharBlock statementPosition) const {
403 return branchTargets_.find(statementPosition) != branchTargets_.end();
404 }
405
406private:
407 struct ScopeIndexComparator {
408 bool operator()(parser::CharBlock, parser::CharBlock) const;
409 };
410 using ScopeIndex =
411 std::multimap<parser::CharBlock, Scope &, ScopeIndexComparator>;
412 ScopeIndex::iterator SearchScopeIndex(parser::CharBlock);
413
414 parser::Message *CheckIndexVarRedefine(
416 void CheckError(const Symbol &);
417
418 std::set<parser::CharBlock, ScopeIndexComparator> branchTargets_;
419 const common::IntrinsicTypeDefaultKinds &defaultKinds_;
420 const common::LanguageFeatureControl &languageFeatures_;
421 const common::LangOptions &langOpts_;
422 parser::AllCookedSources &allCookedSources_;
423 std::string openAccDefaultNoneScalarsStrictDisableOption_;
424 std::optional<parser::CharBlock> location_;
425 std::vector<std::string> searchDirectories_;
426 std::vector<std::string> intrinsicModuleDirectories_;
427 std::vector<std::string> implicitUseModules_;
428 std::string moduleDirectory_{"."s};
429 std::string moduleFileSuffix_{".mod"};
430 std::string targetTriple_;
431 std::string targetFeatures_;
432 bool underscoring_{true};
433 bool warnOnNonstandardUsage_{false};
434 bool warningsAreErrors_{false};
435 bool debugModuleWriter_{false};
436 const evaluate::IntrinsicProcTable intrinsics_;
437 evaluate::TargetCharacteristics targetCharacteristics_;
438 Scope globalScope_;
439 Scope &intrinsicModulesScope_;
440 Scope *currentHermeticModuleFileScope_{nullptr};
441 ScopeIndex scopeIndex_;
442 parser::Messages messages_;
443 std::size_t maxErrors_{0};
444 evaluate::FoldingContext foldingContext_;
445 ConstructStack constructStack_;
446 struct IndexVarInfo {
447 parser::CharBlock location;
448 IndexVarKind kind;
449 };
450 std::map<SymbolRef, const IndexVarInfo, SymbolAddressCompare>
451 activeIndexVars_;
452 UnorderedSymbolSet errorSymbols_;
453 std::set<std::string> tempNames_;
454 const Scope *builtinsScope_{nullptr}; // module __Fortran_builtins
455 Scope *ppcBuiltinTypesScope_{nullptr}; // module __Fortran_PPC_types
456 std::optional<const Scope *> cudaBuiltinsScope_; // module __CUDA_builtins
457 std::optional<const Scope *> cudaDeviceScope_; // module cudadevice
458 const Scope *ppcBuiltinsScope_{nullptr}; // module __ppc_intrinsics
459 std::list<parser::Program> modFileParseTrees_;
460 std::unique_ptr<CommonBlockMap> commonBlockMap_;
461 ModuleDependences moduleDependences_;
462 std::map<const Symbol *, SourceName> moduleFileOutputRenamings_;
463 UnorderedSymbolSet isDefined_;
464 UnorderedSymbolSet isUsed_;
465 std::set<const parser::AccObject *> accObjectDuplicates_;
466 std::list<ProgramTree> programTrees_;
467};
468
469class Semantics {
470public:
471 explicit Semantics(SemanticsContext &context, parser::Program &program)
472 : context_{context}, program_{program} {}
473 Semantics &set_hermeticModuleFileOutput(bool yes = true) {
474 hermeticModuleFileOutput_ = yes;
475 return *this;
476 }
477
478 SemanticsContext &context() const { return context_; }
479 bool Perform();
480 const Scope &FindScope(const parser::CharBlock &where) const {
481 return context_.FindScope(where);
482 }
483 bool AnyFatalError() const { return context_.AnyFatalError(); }
484 void EmitMessages(llvm::raw_ostream &);
485 void DumpSymbols(llvm::raw_ostream &);
486 void DumpSymbolsSources(llvm::raw_ostream &) const;
487
488private:
489 SemanticsContext &context_;
490 parser::Program &program_;
491 bool hermeticModuleFileOutput_{false};
492};
493
494// Base class for semantics checkers.
496 template <typename N> void Enter(const N &) {}
497 template <typename N> void Leave(const N &) {}
498};
499} // namespace Fortran::semantics
500#endif
Definition default-kinds.h:26
Definition LangOptions.h:71
Definition Fortran-features.h:100
Definition common.h:217
Definition provenance.h:286
Definition char-block.h:26
Definition message.h:397
Definition message.h:56
Definition message.h:200
Definition message.h:332
Definition semantics.cpp:285
Definition module-dependences.h:21
Definition program-tree.h:31
Definition scope.h:68
Definition semantics.h:67
Definition symbol.h:907
Definition bit-population-count.h:20
FPMaxminBehavior
Definition FPMaxminBehavior.h:29
Definition check-expression.h:19
Definition parse-tree.h:5705
Definition parse-tree.h:2203
Definition parse-tree.h:2225
Definition parse-tree.h:2466
Definition parse-tree.h:2256
Definition parse-tree.h:2272
Definition parse-tree.h:2368
Definition parse-tree.h:2173
Definition parse-tree.h:2402
Definition parse-tree.h:592
Definition parse-tree.h:2501
Definition parse-tree.h:2535
Definition parse-tree.h:1898
Definition parse-tree.h:2120
Definition semantics.h:495