Warning: This file is not a C or C++ file. It does not have highlighting.
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 "scope.h" |
13 | #include "symbol.h" |
14 | #include "flang/Common/Fortran-features.h" |
15 | #include "flang/Evaluate/common.h" |
16 | #include "flang/Evaluate/intrinsics.h" |
17 | #include "flang/Evaluate/target.h" |
18 | #include "flang/Parser/message.h" |
19 | #include "flang/Semantics/module-dependences.h" |
20 | #include <iosfwd> |
21 | #include <set> |
22 | #include <string> |
23 | #include <vector> |
24 | |
25 | namespace llvm { |
26 | class raw_ostream; |
27 | } |
28 | |
29 | namespace Fortran::common { |
30 | class IntrinsicTypeDefaultKinds; |
31 | } |
32 | |
33 | namespace Fortran::parser { |
34 | struct Name; |
35 | struct Program; |
36 | class AllCookedSources; |
37 | struct AssociateConstruct; |
38 | struct BlockConstruct; |
39 | struct CaseConstruct; |
40 | struct DoConstruct; |
41 | struct ChangeTeamConstruct; |
42 | struct CriticalConstruct; |
43 | struct ForallConstruct; |
44 | struct IfConstruct; |
45 | struct SelectRankConstruct; |
46 | struct SelectTypeConstruct; |
47 | struct Variable; |
48 | struct WhereConstruct; |
49 | } // namespace Fortran::parser |
50 | |
51 | namespace Fortran::semantics { |
52 | |
53 | class Symbol; |
54 | class CommonBlockMap; |
55 | using CommonBlockList = std::vector<std::pair<SymbolRef, std::size_t>>; |
56 | |
57 | using ConstructNode = std::variant<const parser::AssociateConstruct *, |
58 | const parser::BlockConstruct *, const parser::CaseConstruct *, |
59 | const parser::ChangeTeamConstruct *, const parser::CriticalConstruct *, |
60 | const parser::DoConstruct *, const parser::ForallConstruct *, |
61 | const parser::IfConstruct *, const parser::SelectRankConstruct *, |
62 | const parser::SelectTypeConstruct *, const parser::WhereConstruct *>; |
63 | using ConstructStack = std::vector<ConstructNode>; |
64 | |
65 | class SemanticsContext { |
66 | public: |
67 | SemanticsContext(const common::IntrinsicTypeDefaultKinds &, |
68 | const common::LanguageFeatureControl &, parser::AllCookedSources &); |
69 | ~SemanticsContext(); |
70 | |
71 | const common::IntrinsicTypeDefaultKinds &defaultKinds() const { |
72 | return defaultKinds_; |
73 | } |
74 | const common::LanguageFeatureControl &languageFeatures() const { |
75 | return languageFeatures_; |
76 | }; |
77 | int GetDefaultKind(TypeCategory) const; |
78 | int doublePrecisionKind() const { |
79 | return defaultKinds_.doublePrecisionKind(); |
80 | } |
81 | int quadPrecisionKind() const { return defaultKinds_.quadPrecisionKind(); } |
82 | bool IsEnabled(common::LanguageFeature feature) const { |
83 | return languageFeatures_.IsEnabled(feature); |
84 | } |
85 | template <typename A> bool ShouldWarn(A x) const { |
86 | return languageFeatures_.ShouldWarn(x); |
87 | } |
88 | const std::optional<parser::CharBlock> &location() const { return location_; } |
89 | const std::vector<std::string> &searchDirectories() const { |
90 | return searchDirectories_; |
91 | } |
92 | const std::vector<std::string> &intrinsicModuleDirectories() const { |
93 | return intrinsicModuleDirectories_; |
94 | } |
95 | const std::string &moduleDirectory() const { return moduleDirectory_; } |
96 | const std::string &moduleFileSuffix() const { return moduleFileSuffix_; } |
97 | bool underscoring() const { return underscoring_; } |
98 | bool warningsAreErrors() const { return warningsAreErrors_; } |
99 | bool debugModuleWriter() const { return debugModuleWriter_; } |
100 | const evaluate::IntrinsicProcTable &intrinsics() const { return intrinsics_; } |
101 | const evaluate::TargetCharacteristics &targetCharacteristics() const { |
102 | return targetCharacteristics_; |
103 | } |
104 | evaluate::TargetCharacteristics &targetCharacteristics() { |
105 | return targetCharacteristics_; |
106 | } |
107 | Scope &globalScope() { return globalScope_; } |
108 | Scope &intrinsicModulesScope() { return intrinsicModulesScope_; } |
109 | parser::Messages &messages() { return messages_; } |
110 | evaluate::FoldingContext &foldingContext() { return foldingContext_; } |
111 | parser::AllCookedSources &allCookedSources() { return allCookedSources_; } |
112 | ModuleDependences &moduleDependences() { return moduleDependences_; } |
113 | |
114 | SemanticsContext &set_location( |
115 | const std::optional<parser::CharBlock> &location) { |
116 | location_ = location; |
117 | return *this; |
118 | } |
119 | SemanticsContext &set_searchDirectories(const std::vector<std::string> &x) { |
120 | searchDirectories_ = x; |
121 | return *this; |
122 | } |
123 | SemanticsContext &set_intrinsicModuleDirectories( |
124 | const std::vector<std::string> &x) { |
125 | intrinsicModuleDirectories_ = x; |
126 | return *this; |
127 | } |
128 | SemanticsContext &set_moduleDirectory(const std::string &x) { |
129 | moduleDirectory_ = x; |
130 | return *this; |
131 | } |
132 | SemanticsContext &set_moduleFileSuffix(const std::string &x) { |
133 | moduleFileSuffix_ = x; |
134 | return *this; |
135 | } |
136 | SemanticsContext &set_underscoring(bool x) { |
137 | underscoring_ = x; |
138 | return *this; |
139 | } |
140 | SemanticsContext &set_warnOnNonstandardUsage(bool x) { |
141 | warnOnNonstandardUsage_ = x; |
142 | return *this; |
143 | } |
144 | SemanticsContext &set_warningsAreErrors(bool x) { |
145 | warningsAreErrors_ = x; |
146 | return *this; |
147 | } |
148 | |
149 | SemanticsContext &set_debugModuleWriter(bool x) { |
150 | debugModuleWriter_ = x; |
151 | return *this; |
152 | } |
153 | |
154 | const DeclTypeSpec &MakeNumericType(TypeCategory, int kind = 0); |
155 | const DeclTypeSpec &MakeLogicalType(int kind = 0); |
156 | |
157 | bool AnyFatalError() const; |
158 | |
159 | // Test or set the Error flag on a Symbol |
160 | bool HasError(const Symbol &); |
161 | bool HasError(const Symbol *); |
162 | bool HasError(const parser::Name &); |
163 | void SetError(const Symbol &, bool = true); |
164 | |
165 | template <typename... A> parser::Message &Say(A &&...args) { |
166 | CHECK(location_); |
167 | return messages_.Say(*location_, std::forward<A>(args)...); |
168 | } |
169 | template <typename... A> |
170 | parser::Message &Say(parser::CharBlock at, A &&...args) { |
171 | return messages_.Say(at, std::forward<A>(args)...); |
172 | } |
173 | parser::Message &Say(parser::Message &&msg) { |
174 | return messages_.Say(std::move(msg)); |
175 | } |
176 | template <typename... A> |
177 | parser::Message &SayWithDecl(const Symbol &symbol, |
178 | const parser::CharBlock &at, parser::MessageFixedText &&msg, |
179 | A &&...args) { |
180 | auto &message{Say(at, std::move(msg), args...)}; |
181 | evaluate::AttachDeclaration(&message, symbol); |
182 | return message; |
183 | } |
184 | |
185 | const Scope &FindScope(parser::CharBlock) const; |
186 | Scope &FindScope(parser::CharBlock); |
187 | void UpdateScopeIndex(Scope &, parser::CharBlock); |
188 | |
189 | bool IsInModuleFile(parser::CharBlock) const; |
190 | |
191 | const ConstructStack &constructStack() const { return constructStack_; } |
192 | template <typename N> void PushConstruct(const N &node) { |
193 | constructStack_.emplace_back(&node); |
194 | } |
195 | void PopConstruct(); |
196 | |
197 | ENUM_CLASS(IndexVarKind, DO, FORALL) |
198 | // Check to see if a variable being redefined is a DO or FORALL index. |
199 | // If so, emit a message. |
200 | void WarnIndexVarRedefine(const parser::CharBlock &, const Symbol &); |
201 | void CheckIndexVarRedefine(const parser::CharBlock &, const Symbol &); |
202 | void CheckIndexVarRedefine(const parser::Variable &); |
203 | void CheckIndexVarRedefine(const parser::Name &); |
204 | void ActivateIndexVar(const parser::Name &, IndexVarKind); |
205 | void DeactivateIndexVar(const parser::Name &); |
206 | SymbolVector GetIndexVars(IndexVarKind); |
207 | SourceName SaveTempName(std::string &&); |
208 | SourceName GetTempName(const Scope &); |
209 | static bool IsTempName(const std::string &); |
210 | |
211 | // Locate and process the contents of a built-in module on demand |
212 | Scope *GetBuiltinModule(const char *name); |
213 | |
214 | // Defines builtinsScope_ from the __Fortran_builtins module |
215 | void UseFortranBuiltinsModule(); |
216 | const Scope *GetBuiltinsScope() const { return builtinsScope_; } |
217 | |
218 | void UsePPCBuiltinTypesModule(); |
219 | const Scope &GetCUDABuiltinsScope(); |
220 | void UsePPCBuiltinsModule(); |
221 | Scope *GetPPCBuiltinTypesScope() { return ppcBuiltinTypesScope_; } |
222 | const Scope *GetPPCBuiltinsScope() const { return ppcBuiltinsScope_; } |
223 | |
224 | // Saves a module file's parse tree so that it remains available |
225 | // during semantics. |
226 | parser::Program &SaveParseTree(parser::Program &&); |
227 | |
228 | // Ensures a common block definition does not conflict with previous |
229 | // appearances in the program and consolidate information about |
230 | // common blocks at the program level for later checks and lowering. |
231 | // This can obviously not check any conflicts between different compilation |
232 | // units (in case such conflicts exist, the behavior will depend on the |
233 | // linker). |
234 | void MapCommonBlockAndCheckConflicts(const Symbol &); |
235 | |
236 | // Get the list of common blocks appearing in the program. If a common block |
237 | // appears in several subprograms, only one of its appearance is returned in |
238 | // the list alongside the biggest byte size of all its appearances. |
239 | // If a common block is initialized in any of its appearances, the list will |
240 | // contain the appearance with the initialization, otherwise the appearance |
241 | // with the biggest size is returned. The extra byte size information allows |
242 | // handling the case where the common block initialization is not the |
243 | // appearance with the biggest size: the common block will have the biggest |
244 | // size with the first bytes initialized with the initial value. This is not |
245 | // standard, if the initialization and biggest size appearances are in |
246 | // different compilation units, the behavior will depend on the linker. The |
247 | // linker may have the behavior described before, but it may also keep the |
248 | // initialized common symbol without extending its size, or have some other |
249 | // behavior. |
250 | CommonBlockList GetCommonBlocks() const; |
251 | |
252 | private: |
253 | struct ScopeIndexComparator { |
254 | bool operator()(parser::CharBlock, parser::CharBlock) const; |
255 | }; |
256 | using ScopeIndex = |
257 | std::multimap<parser::CharBlock, Scope &, ScopeIndexComparator>; |
258 | ScopeIndex::iterator SearchScopeIndex(parser::CharBlock); |
259 | |
260 | void CheckIndexVarRedefine( |
261 | const parser::CharBlock &, const Symbol &, parser::MessageFixedText &&); |
262 | void CheckError(const Symbol &); |
263 | |
264 | const common::IntrinsicTypeDefaultKinds &defaultKinds_; |
265 | const common::LanguageFeatureControl &languageFeatures_; |
266 | parser::AllCookedSources &allCookedSources_; |
267 | std::optional<parser::CharBlock> location_; |
268 | std::vector<std::string> searchDirectories_; |
269 | std::vector<std::string> intrinsicModuleDirectories_; |
270 | std::string moduleDirectory_{"."s}; |
271 | std::string moduleFileSuffix_{".mod"}; |
272 | bool underscoring_{true}; |
273 | bool warnOnNonstandardUsage_{false}; |
274 | bool warningsAreErrors_{false}; |
275 | bool debugModuleWriter_{false}; |
276 | const evaluate::IntrinsicProcTable intrinsics_; |
277 | evaluate::TargetCharacteristics targetCharacteristics_; |
278 | Scope globalScope_; |
279 | Scope &intrinsicModulesScope_; |
280 | ScopeIndex scopeIndex_; |
281 | parser::Messages messages_; |
282 | evaluate::FoldingContext foldingContext_; |
283 | ConstructStack constructStack_; |
284 | struct IndexVarInfo { |
285 | parser::CharBlock location; |
286 | IndexVarKind kind; |
287 | }; |
288 | std::map<SymbolRef, const IndexVarInfo, SymbolAddressCompare> |
289 | activeIndexVars_; |
290 | UnorderedSymbolSet errorSymbols_; |
291 | std::set<std::string> tempNames_; |
292 | const Scope *builtinsScope_{nullptr}; // module __Fortran_builtins |
293 | Scope *ppcBuiltinTypesScope_{nullptr}; // module __Fortran_PPC_types |
294 | std::optional<const Scope *> cudaBuiltinsScope_; // module __CUDA_builtins |
295 | const Scope *ppcBuiltinsScope_{nullptr}; // module __ppc_intrinsics |
296 | std::list<parser::Program> modFileParseTrees_; |
297 | std::unique_ptr<CommonBlockMap> commonBlockMap_; |
298 | ModuleDependences moduleDependences_; |
299 | }; |
300 | |
301 | class Semantics { |
302 | public: |
303 | explicit Semantics(SemanticsContext &context, parser::Program &program, |
304 | bool debugModuleWriter = false) |
305 | : context_{context}, program_{program} { |
306 | context.set_debugModuleWriter(debugModuleWriter); |
307 | } |
308 | |
309 | SemanticsContext &context() const { return context_; } |
310 | bool Perform(); |
311 | const Scope &FindScope(const parser::CharBlock &where) const { |
312 | return context_.FindScope(where); |
313 | } |
314 | bool AnyFatalError() const { return context_.AnyFatalError(); } |
315 | void EmitMessages(llvm::raw_ostream &) const; |
316 | void DumpSymbols(llvm::raw_ostream &); |
317 | void DumpSymbolsSources(llvm::raw_ostream &) const; |
318 | |
319 | private: |
320 | SemanticsContext &context_; |
321 | parser::Program &program_; |
322 | }; |
323 | |
324 | // Base class for semantics checkers. |
325 | struct BaseChecker { |
326 | template <typename N> void Enter(const N &) {} |
327 | template <typename N> void Leave(const N &) {} |
328 | }; |
329 | } // namespace Fortran::semantics |
330 | #endif |
331 |
Warning: This file is not a C or C++ file. It does not have highlighting.