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