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