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/Parser/message.h"
18 #include <iosfwd>
19 #include <set>
20 #include <string>
21 #include <vector>
22 
23 namespace llvm {
24 class raw_ostream;
25 }
26 
27 namespace Fortran::common {
28 class IntrinsicTypeDefaultKinds;
29 }
30 
31 namespace Fortran::parser {
32 struct Name;
33 struct Program;
34 class AllCookedSources;
35 struct AssociateConstruct;
36 struct BlockConstruct;
37 struct CaseConstruct;
38 struct DoConstruct;
39 struct ChangeTeamConstruct;
40 struct CriticalConstruct;
41 struct ForallConstruct;
42 struct IfConstruct;
43 struct SelectRankConstruct;
44 struct SelectTypeConstruct;
45 struct Variable;
46 struct WhereConstruct;
47 } // namespace Fortran::parser
48 
49 namespace Fortran::semantics {
50 
51 class Symbol;
52 
53 using ConstructNode = std::variant<const parser::AssociateConstruct *,
54     const parser::BlockConstruct *, const parser::CaseConstruct *,
55     const parser::ChangeTeamConstruct *, const parser::CriticalConstruct *,
56     const parser::DoConstruct *, const parser::ForallConstruct *,
57     const parser::IfConstruct *, const parser::SelectRankConstruct *,
58     const parser::SelectTypeConstruct *, const parser::WhereConstruct *>;
59 using ConstructStack = std::vector<ConstructNode>;
60 
61 class SemanticsContext {
62 public:
63   SemanticsContext(const common::IntrinsicTypeDefaultKinds &,
64       const common::LanguageFeatureControl &, parser::AllCookedSources &);
65   ~SemanticsContext();
66 
defaultKinds()67   const common::IntrinsicTypeDefaultKinds &defaultKinds() const {
68     return defaultKinds_;
69   }
languageFeatures()70   const common::LanguageFeatureControl &languageFeatures() const {
71     return languageFeatures_;
72   };
73   int GetDefaultKind(TypeCategory) const;
doublePrecisionKind()74   int doublePrecisionKind() const {
75     return defaultKinds_.doublePrecisionKind();
76   }
quadPrecisionKind()77   int quadPrecisionKind() const { return defaultKinds_.quadPrecisionKind(); }
78   bool IsEnabled(common::LanguageFeature) const;
79   bool ShouldWarn(common::LanguageFeature) const;
location()80   const std::optional<parser::CharBlock> &location() const { return location_; }
searchDirectories()81   const std::vector<std::string> &searchDirectories() const {
82     return searchDirectories_;
83   }
moduleDirectory()84   const std::string &moduleDirectory() const { return moduleDirectory_; }
moduleFileSuffix()85   const std::string &moduleFileSuffix() const { return moduleFileSuffix_; }
warnOnNonstandardUsage()86   bool warnOnNonstandardUsage() const { return warnOnNonstandardUsage_; }
warningsAreErrors()87   bool warningsAreErrors() const { return warningsAreErrors_; }
debugModuleWriter()88   bool debugModuleWriter() const { return debugModuleWriter_; }
intrinsics()89   const evaluate::IntrinsicProcTable &intrinsics() const { return intrinsics_; }
globalScope()90   Scope &globalScope() { return globalScope_; }
messages()91   parser::Messages &messages() { return messages_; }
foldingContext()92   evaluate::FoldingContext &foldingContext() { return foldingContext_; }
allCookedSources()93   parser::AllCookedSources &allCookedSources() { return allCookedSources_; }
94 
set_location(const std::optional<parser::CharBlock> & location)95   SemanticsContext &set_location(
96       const std::optional<parser::CharBlock> &location) {
97     location_ = location;
98     return *this;
99   }
set_searchDirectories(const std::vector<std::string> & x)100   SemanticsContext &set_searchDirectories(const std::vector<std::string> &x) {
101     searchDirectories_ = x;
102     return *this;
103   }
set_moduleDirectory(const std::string & x)104   SemanticsContext &set_moduleDirectory(const std::string &x) {
105     moduleDirectory_ = x;
106     return *this;
107   }
set_moduleFileSuffix(const std::string & x)108   SemanticsContext &set_moduleFileSuffix(const std::string &x) {
109     moduleFileSuffix_ = x;
110     return *this;
111   }
set_warnOnNonstandardUsage(bool x)112   SemanticsContext &set_warnOnNonstandardUsage(bool x) {
113     warnOnNonstandardUsage_ = x;
114     return *this;
115   }
set_warningsAreErrors(bool x)116   SemanticsContext &set_warningsAreErrors(bool x) {
117     warningsAreErrors_ = x;
118     return *this;
119   }
120 
set_debugModuleWriter(bool x)121   SemanticsContext &set_debugModuleWriter(bool x) {
122     debugModuleWriter_ = x;
123     return *this;
124   }
125 
126   const DeclTypeSpec &MakeNumericType(TypeCategory, int kind = 0);
127   const DeclTypeSpec &MakeLogicalType(int kind = 0);
128 
129   bool AnyFatalError() const;
130 
131   // Test or set the Error flag on a Symbol
132   bool HasError(const Symbol &);
133   bool HasError(const Symbol *);
134   bool HasError(const parser::Name &);
135   void SetError(const Symbol &, bool = true);
136 
Say(A &&...args)137   template <typename... A> parser::Message &Say(A &&...args) {
138     CHECK(location_);
139     return messages_.Say(*location_, std::forward<A>(args)...);
140   }
141   template <typename... A>
Say(parser::CharBlock at,A &&...args)142   parser::Message &Say(parser::CharBlock at, A &&...args) {
143     return messages_.Say(at, std::forward<A>(args)...);
144   }
Say(parser::Message && msg)145   parser::Message &Say(parser::Message &&msg) {
146     return messages_.Say(std::move(msg));
147   }
148   template <typename... A>
SayWithDecl(const Symbol & symbol,const parser::CharBlock & at,parser::MessageFixedText && msg,A &&...args)149   void SayWithDecl(const Symbol &symbol, const parser::CharBlock &at,
150       parser::MessageFixedText &&msg, A &&...args) {
151     auto &message{Say(at, std::move(msg), args...)};
152     evaluate::AttachDeclaration(&message, symbol);
153   }
154 
155   const Scope &FindScope(parser::CharBlock) const;
156   Scope &FindScope(parser::CharBlock);
157 
constructStack()158   const ConstructStack &constructStack() const { return constructStack_; }
PushConstruct(const N & node)159   template <typename N> void PushConstruct(const N &node) {
160     constructStack_.emplace_back(&node);
161   }
162   void PopConstruct();
163 
164   ENUM_CLASS(IndexVarKind, DO, FORALL)
165   // Check to see if a variable being redefined is a DO or FORALL index.
166   // If so, emit a message.
167   void WarnIndexVarRedefine(const parser::CharBlock &, const Symbol &);
168   void CheckIndexVarRedefine(const parser::CharBlock &, const Symbol &);
169   void CheckIndexVarRedefine(const parser::Variable &);
170   void CheckIndexVarRedefine(const parser::Name &);
171   void ActivateIndexVar(const parser::Name &, IndexVarKind);
172   void DeactivateIndexVar(const parser::Name &);
173   SymbolVector GetIndexVars(IndexVarKind);
174   SourceName SaveTempName(std::string &&);
175   SourceName GetTempName(const Scope &);
176 
177 private:
178   void CheckIndexVarRedefine(
179       const parser::CharBlock &, const Symbol &, parser::MessageFixedText &&);
180   void CheckError(const Symbol &);
181 
182   const common::IntrinsicTypeDefaultKinds &defaultKinds_;
183   const common::LanguageFeatureControl languageFeatures_;
184   parser::AllCookedSources &allCookedSources_;
185   std::optional<parser::CharBlock> location_;
186   std::vector<std::string> searchDirectories_;
187   std::string moduleDirectory_{"."s};
188   std::string moduleFileSuffix_{".mod"};
189   bool warnOnNonstandardUsage_{false};
190   bool warningsAreErrors_{false};
191   bool debugModuleWriter_{false};
192   const evaluate::IntrinsicProcTable intrinsics_;
193   Scope globalScope_;
194   parser::Messages messages_;
195   evaluate::FoldingContext foldingContext_;
196   ConstructStack constructStack_;
197   struct IndexVarInfo {
198     parser::CharBlock location;
199     IndexVarKind kind;
200   };
201   std::map<SymbolRef, const IndexVarInfo> activeIndexVars_;
202   std::set<SymbolRef> errorSymbols_;
203   std::set<std::string> tempNames_;
204 };
205 
206 class Semantics {
207 public:
208   explicit Semantics(SemanticsContext &context, parser::Program &program,
209       parser::CharBlock charBlock, bool debugModuleWriter = false)
210       : context_{context}, program_{program} {
211     context.set_debugModuleWriter(debugModuleWriter);
212     context.globalScope().AddSourceRange(charBlock);
213   }
214 
context()215   SemanticsContext &context() const { return context_; }
216   bool Perform();
FindScope(const parser::CharBlock & where)217   const Scope &FindScope(const parser::CharBlock &where) const {
218     return context_.FindScope(where);
219   }
AnyFatalError()220   bool AnyFatalError() const { return context_.AnyFatalError(); }
221   void EmitMessages(llvm::raw_ostream &) const;
222   void DumpSymbols(llvm::raw_ostream &);
223   void DumpSymbolsSources(llvm::raw_ostream &) const;
224 
225 private:
226   SemanticsContext &context_;
227   parser::Program &program_;
228 };
229 
230 // Base class for semantics checkers.
231 struct BaseChecker {
EnterBaseChecker232   template <typename N> void Enter(const N &) {}
LeaveBaseChecker233   template <typename N> void Leave(const N &) {}
234 };
235 } // namespace Fortran::semantics
236 #endif
237