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