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