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