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