llvm-project

Форк
0
478 строк · 15.0 Кб
1
//===-- lib/Semantics/scope.cpp -------------------------------------------===//
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
#include "flang/Semantics/scope.h"
10
#include "flang/Parser/characters.h"
11
#include "flang/Semantics/semantics.h"
12
#include "flang/Semantics/symbol.h"
13
#include "flang/Semantics/type.h"
14
#include "llvm/Support/raw_ostream.h"
15
#include <algorithm>
16
#include <memory>
17

18
namespace Fortran::semantics {
19

20
Symbols<1024> Scope::allSymbols;
21

22
bool EquivalenceObject::operator==(const EquivalenceObject &that) const {
23
  return symbol == that.symbol && subscripts == that.subscripts &&
24
      substringStart == that.substringStart;
25
}
26

27
bool EquivalenceObject::operator<(const EquivalenceObject &that) const {
28
  return &symbol < &that.symbol ||
29
      (&symbol == &that.symbol &&
30
          (subscripts < that.subscripts ||
31
              (subscripts == that.subscripts &&
32
                  substringStart < that.substringStart)));
33
}
34

35
std::string EquivalenceObject::AsFortran() const {
36
  std::string buf;
37
  llvm::raw_string_ostream ss{buf};
38
  ss << symbol.name().ToString();
39
  if (!subscripts.empty()) {
40
    char sep{'('};
41
    for (auto subscript : subscripts) {
42
      ss << sep << subscript;
43
      sep = ',';
44
    }
45
    ss << ')';
46
  }
47
  if (substringStart) {
48
    ss << '(' << *substringStart << ":)";
49
  }
50
  return ss.str();
51
}
52

53
Scope &Scope::MakeScope(Kind kind, Symbol *symbol) {
54
  return children_.emplace_back(*this, kind, symbol, context_);
55
}
56

57
template <typename T>
58
static std::vector<common::Reference<T>> GetSortedSymbols(
59
    const std::map<SourceName, MutableSymbolRef> &symbols) {
60
  std::vector<common::Reference<T>> result;
61
  result.reserve(symbols.size());
62
  for (auto &pair : symbols) {
63
    result.push_back(*pair.second);
64
  }
65
  std::sort(result.begin(), result.end(), SymbolSourcePositionCompare{});
66
  return result;
67
}
68

69
MutableSymbolVector Scope::GetSymbols() {
70
  return GetSortedSymbols<Symbol>(symbols_);
71
}
72
SymbolVector Scope::GetSymbols() const {
73
  return GetSortedSymbols<const Symbol>(symbols_);
74
}
75

76
Scope::iterator Scope::find(const SourceName &name) {
77
  return symbols_.find(name);
78
}
79
Scope::size_type Scope::erase(const SourceName &name) {
80
  auto it{symbols_.find(name)};
81
  if (it != end()) {
82
    symbols_.erase(it);
83
    return 1;
84
  } else {
85
    return 0;
86
  }
87
}
88
Symbol *Scope::FindSymbol(const SourceName &name) const {
89
  auto it{find(name)};
90
  if (it != end()) {
91
    return &*it->second;
92
  } else if (IsSubmodule()) {
93
    const Scope *parent{symbol_->get<ModuleDetails>().parent()};
94
    return parent ? parent->FindSymbol(name) : nullptr;
95
  } else if (CanImport(name)) {
96
    return parent_->FindSymbol(name);
97
  } else {
98
    return nullptr;
99
  }
100
}
101

102
Symbol *Scope::FindComponent(SourceName name) const {
103
  CHECK(IsDerivedType());
104
  auto found{find(name)};
105
  if (found != end()) {
106
    return &*found->second;
107
  } else if (const Scope * parent{GetDerivedTypeParent()}) {
108
    return parent->FindComponent(name);
109
  } else {
110
    return nullptr;
111
  }
112
}
113

114
bool Scope::Contains(const Scope &that) const {
115
  for (const Scope *scope{&that};; scope = &scope->parent()) {
116
    if (*scope == *this) {
117
      return true;
118
    }
119
    if (scope->IsGlobal()) {
120
      return false;
121
    }
122
  }
123
}
124

125
Symbol *Scope::CopySymbol(const Symbol &symbol) {
126
  auto pair{try_emplace(symbol.name(), symbol.attrs())};
127
  if (!pair.second) {
128
    return nullptr; // already exists
129
  } else {
130
    Symbol &result{*pair.first->second};
131
    result.flags() = symbol.flags();
132
    result.set_details(common::Clone(symbol.details()));
133
    return &result;
134
  }
135
}
136

137
void Scope::add_equivalenceSet(EquivalenceSet &&set) {
138
  equivalenceSets_.emplace_back(std::move(set));
139
}
140

141
void Scope::add_crayPointer(const SourceName &name, Symbol &pointer) {
142
  CHECK(pointer.test(Symbol::Flag::CrayPointer));
143
  crayPointers_.emplace(name, pointer);
144
}
145

146
Symbol &Scope::MakeCommonBlock(const SourceName &name) {
147
  const auto it{commonBlocks_.find(name)};
148
  if (it != commonBlocks_.end()) {
149
    return *it->second;
150
  } else {
151
    Symbol &symbol{MakeSymbol(name, Attrs{}, CommonBlockDetails{})};
152
    commonBlocks_.emplace(name, symbol);
153
    return symbol;
154
  }
155
}
156
Symbol *Scope::FindCommonBlock(const SourceName &name) const {
157
  const auto it{commonBlocks_.find(name)};
158
  return it != commonBlocks_.end() ? &*it->second : nullptr;
159
}
160

161
Scope *Scope::FindSubmodule(const SourceName &name) const {
162
  auto it{submodules_.find(name)};
163
  if (it == submodules_.end()) {
164
    return nullptr;
165
  } else {
166
    return &*it->second;
167
  }
168
}
169
bool Scope::AddSubmodule(const SourceName &name, Scope &submodule) {
170
  return submodules_.emplace(name, submodule).second;
171
}
172

173
const DeclTypeSpec *Scope::FindType(const DeclTypeSpec &type) const {
174
  auto it{std::find(declTypeSpecs_.begin(), declTypeSpecs_.end(), type)};
175
  return it != declTypeSpecs_.end() ? &*it : nullptr;
176
}
177

178
const DeclTypeSpec &Scope::MakeNumericType(
179
    TypeCategory category, KindExpr &&kind) {
180
  return MakeLengthlessType(NumericTypeSpec{category, std::move(kind)});
181
}
182
const DeclTypeSpec &Scope::MakeLogicalType(KindExpr &&kind) {
183
  return MakeLengthlessType(LogicalTypeSpec{std::move(kind)});
184
}
185
const DeclTypeSpec &Scope::MakeTypeStarType() {
186
  return MakeLengthlessType(DeclTypeSpec{DeclTypeSpec::TypeStar});
187
}
188
const DeclTypeSpec &Scope::MakeClassStarType() {
189
  return MakeLengthlessType(DeclTypeSpec{DeclTypeSpec::ClassStar});
190
}
191
// Types that can't have length parameters can be reused without having to
192
// compare length expressions. They are stored in the global scope.
193
const DeclTypeSpec &Scope::MakeLengthlessType(DeclTypeSpec &&type) {
194
  const auto *found{FindType(type)};
195
  return found ? *found : declTypeSpecs_.emplace_back(std::move(type));
196
}
197

198
const DeclTypeSpec &Scope::MakeCharacterType(
199
    ParamValue &&length, KindExpr &&kind) {
200
  return declTypeSpecs_.emplace_back(
201
      CharacterTypeSpec{std::move(length), std::move(kind)});
202
}
203

204
DeclTypeSpec &Scope::MakeDerivedType(
205
    DeclTypeSpec::Category category, DerivedTypeSpec &&spec) {
206
  return declTypeSpecs_.emplace_back(category, std::move(spec));
207
}
208

209
const DeclTypeSpec *Scope::GetType(const SomeExpr &expr) {
210
  if (auto dyType{expr.GetType()}) {
211
    if (dyType->IsAssumedType()) {
212
      return &MakeTypeStarType();
213
    } else if (dyType->IsUnlimitedPolymorphic()) {
214
      return &MakeClassStarType();
215
    } else {
216
      switch (dyType->category()) {
217
      case TypeCategory::Integer:
218
      case TypeCategory::Real:
219
      case TypeCategory::Complex:
220
        return &MakeNumericType(dyType->category(), KindExpr{dyType->kind()});
221
      case TypeCategory::Character:
222
        if (const ParamValue * lenParam{dyType->charLengthParamValue()}) {
223
          return &MakeCharacterType(
224
              ParamValue{*lenParam}, KindExpr{dyType->kind()});
225
        } else {
226
          auto lenExpr{dyType->GetCharLength()};
227
          if (!lenExpr) {
228
            lenExpr =
229
                std::get<evaluate::Expr<evaluate::SomeCharacter>>(expr.u).LEN();
230
          }
231
          if (lenExpr) {
232
            return &MakeCharacterType(
233
                ParamValue{SomeIntExpr{std::move(*lenExpr)},
234
                    common::TypeParamAttr::Len},
235
                KindExpr{dyType->kind()});
236
          }
237
        }
238
        break;
239
      case TypeCategory::Logical:
240
        return &MakeLogicalType(KindExpr{dyType->kind()});
241
      case TypeCategory::Derived:
242
        return &MakeDerivedType(dyType->IsPolymorphic()
243
                ? DeclTypeSpec::ClassDerived
244
                : DeclTypeSpec::TypeDerived,
245
            DerivedTypeSpec{dyType->GetDerivedTypeSpec()});
246
      }
247
    }
248
  }
249
  return nullptr;
250
}
251

252
Scope::ImportKind Scope::GetImportKind() const {
253
  if (importKind_) {
254
    return *importKind_;
255
  }
256
  if (symbol_ && !symbol_->attrs().test(Attr::MODULE)) {
257
    if (auto *details{symbol_->detailsIf<SubprogramDetails>()}) {
258
      if (details->isInterface()) {
259
        return ImportKind::None; // default for non-mod-proc interface body
260
      }
261
    }
262
  }
263
  return ImportKind::Default;
264
}
265

266
std::optional<parser::MessageFixedText> Scope::SetImportKind(ImportKind kind) {
267
  if (!importKind_) {
268
    importKind_ = kind;
269
    return std::nullopt;
270
  }
271
  bool hasNone{kind == ImportKind::None || *importKind_ == ImportKind::None};
272
  bool hasAll{kind == ImportKind::All || *importKind_ == ImportKind::All};
273
  // Check C8100 and C898: constraints on multiple IMPORT statements
274
  if (hasNone || hasAll) {
275
    return hasNone
276
        ? "IMPORT,NONE must be the only IMPORT statement in a scope"_err_en_US
277
        : "IMPORT,ALL must be the only IMPORT statement in a scope"_err_en_US;
278
  } else if (kind != *importKind_ &&
279
      (kind != ImportKind::Only && *importKind_ != ImportKind::Only)) {
280
    return "Every IMPORT must have ONLY specifier if one of them does"_err_en_US;
281
  } else {
282
    return std::nullopt;
283
  }
284
}
285

286
void Scope::add_importName(const SourceName &name) {
287
  importNames_.insert(name);
288
}
289

290
// true if name can be imported or host-associated from parent scope.
291
bool Scope::CanImport(const SourceName &name) const {
292
  if (IsTopLevel() || parent_->IsTopLevel()) {
293
    return false;
294
  }
295
  switch (GetImportKind()) {
296
    SWITCH_COVERS_ALL_CASES
297
  case ImportKind::None:
298
    return false;
299
  case ImportKind::All:
300
  case ImportKind::Default:
301
    return true;
302
  case ImportKind::Only:
303
    return importNames_.count(name) > 0;
304
  }
305
}
306

307
void Scope::AddSourceRange(parser::CharBlock source) {
308
  if (source.empty()) {
309
    return;
310
  }
311
  const parser::AllCookedSources &allCookedSources{context_.allCookedSources()};
312
  const parser::CookedSource *cooked{allCookedSources.Find(source)};
313
  if (!cooked) {
314
    CHECK(context_.IsTempName(source.ToString()));
315
    return;
316
  }
317
  for (auto *scope{this}; !scope->IsTopLevel(); scope = &scope->parent()) {
318
    CHECK(scope->sourceRange_.empty() == (scope->cookedSource_ == nullptr));
319
    if (!scope->cookedSource_) {
320
      context_.UpdateScopeIndex(*scope, source);
321
      scope->cookedSource_ = cooked;
322
      scope->sourceRange_ = source;
323
    } else if (scope->cookedSource_ == cooked) {
324
      auto combined{scope->sourceRange()};
325
      combined.ExtendToCover(source);
326
      context_.UpdateScopeIndex(*scope, combined);
327
      scope->sourceRange_ = combined;
328
    } else {
329
      // There's a bug that will be hard to fix; crash informatively
330
      const parser::AllSources &allSources{allCookedSources.allSources()};
331
      const auto describe{[&](parser::CharBlock src) {
332
        if (auto range{allCookedSources.GetProvenanceRange(src)}) {
333
          std::size_t offset;
334
          if (const parser::SourceFile *
335
              file{allSources.GetSourceFile(range->start(), &offset)}) {
336
            return "'"s + file->path() + "' at " + std::to_string(offset) +
337
                " for " + std::to_string(range->size());
338
          } else {
339
            return "(GetSourceFile failed)"s;
340
          }
341
        } else {
342
          return "(GetProvenanceRange failed)"s;
343
        }
344
      }};
345
      std::string scopeDesc{describe(scope->sourceRange_)};
346
      std::string newDesc{describe(source)};
347
      common::die("AddSourceRange would have combined ranges from distinct "
348
                  "source files \"%s\" and \"%s\"",
349
          scopeDesc.c_str(), newDesc.c_str());
350
    }
351
    // Note: If the "break;" here were unconditional (or, equivalently, if
352
    // there were no loop at all) then the source ranges of parent scopes
353
    // would not enclose the source ranges of their children.  Timing
354
    // shows that it's cheap to maintain this property, with the exceptions
355
    // of top-level scopes and for (sub)modules and their descendant
356
    // submodules.
357
    if (scope->IsSubmodule()) {
358
      break; // Submodules are child scopes but not contained ranges
359
    }
360
  }
361
}
362

363
llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Scope &scope) {
364
  os << Scope::EnumToString(scope.kind()) << " scope: ";
365
  if (auto *symbol{scope.symbol()}) {
366
    os << *symbol << ' ';
367
  }
368
  if (scope.derivedTypeSpec_) {
369
    os << "instantiation of " << *scope.derivedTypeSpec_ << ' ';
370
  }
371
  os << scope.children_.size() << " children\n";
372
  for (const auto &pair : scope.symbols_) {
373
    const Symbol &symbol{*pair.second};
374
    os << "  " << symbol << '\n';
375
  }
376
  if (!scope.equivalenceSets_.empty()) {
377
    os << "  Equivalence Sets:\n";
378
    for (const auto &set : scope.equivalenceSets_) {
379
      os << "   ";
380
      for (const auto &object : set) {
381
        os << ' ' << object.AsFortran();
382
      }
383
      os << '\n';
384
    }
385
  }
386
  for (const auto &pair : scope.commonBlocks_) {
387
    const Symbol &symbol{*pair.second};
388
    os << "  " << symbol << '\n';
389
  }
390
  return os;
391
}
392

393
bool Scope::IsStmtFunction() const {
394
  return symbol_ && symbol_->test(Symbol::Flag::StmtFunction);
395
}
396

397
template <common::TypeParamAttr... ParamAttr> struct IsTypeParamHelper {
398
  static_assert(sizeof...(ParamAttr) == 0, "must have one or zero template");
399
  static bool IsParam(const Symbol &symbol) {
400
    return symbol.has<TypeParamDetails>();
401
  }
402
};
403

404
template <common::TypeParamAttr ParamAttr> struct IsTypeParamHelper<ParamAttr> {
405
  static bool IsParam(const Symbol &symbol) {
406
    if (const auto *typeParam{symbol.detailsIf<TypeParamDetails>()}) {
407
      return typeParam->attr() == ParamAttr;
408
    }
409
    return false;
410
  }
411
};
412

413
template <common::TypeParamAttr... ParamAttr>
414
static bool IsParameterizedDerivedTypeHelper(const Scope &scope) {
415
  if (scope.IsDerivedType()) {
416
    if (const Scope * parent{scope.GetDerivedTypeParent()}) {
417
      if (IsParameterizedDerivedTypeHelper<ParamAttr...>(*parent)) {
418
        return true;
419
      }
420
    }
421
    for (const auto &nameAndSymbolPair : scope) {
422
      if (IsTypeParamHelper<ParamAttr...>::IsParam(*nameAndSymbolPair.second)) {
423
        return true;
424
      }
425
    }
426
  }
427
  return false;
428
}
429

430
bool Scope::IsParameterizedDerivedType() const {
431
  return IsParameterizedDerivedTypeHelper<>(*this);
432
}
433
bool Scope::IsDerivedTypeWithLengthParameter() const {
434
  return IsParameterizedDerivedTypeHelper<common::TypeParamAttr::Len>(*this);
435
}
436
bool Scope::IsDerivedTypeWithKindParameter() const {
437
  return IsParameterizedDerivedTypeHelper<common::TypeParamAttr::Kind>(*this);
438
}
439

440
const DeclTypeSpec *Scope::FindInstantiatedDerivedType(
441
    const DerivedTypeSpec &spec, DeclTypeSpec::Category category) const {
442
  DeclTypeSpec type{category, spec};
443
  if (const auto *result{FindType(type)}) {
444
    return result;
445
  } else if (IsGlobal()) {
446
    return nullptr;
447
  } else {
448
    return parent().FindInstantiatedDerivedType(spec, category);
449
  }
450
}
451

452
const Scope *Scope::GetDerivedTypeParent() const {
453
  if (const Symbol * symbol{GetSymbol()}) {
454
    if (const DerivedTypeSpec * parent{symbol->GetParentTypeSpec(this)}) {
455
      return parent->scope();
456
    }
457
  }
458
  return nullptr;
459
}
460

461
const Scope &Scope::GetDerivedTypeBase() const {
462
  const Scope *child{this};
463
  for (const Scope *parent{GetDerivedTypeParent()}; parent != nullptr;
464
       parent = child->GetDerivedTypeParent()) {
465
    child = parent;
466
  }
467
  return *child;
468
}
469

470
void Scope::InstantiateDerivedTypes() {
471
  for (DeclTypeSpec &type : declTypeSpecs_) {
472
    if (type.category() == DeclTypeSpec::TypeDerived ||
473
        type.category() == DeclTypeSpec::ClassDerived) {
474
      type.derivedTypeSpec().Instantiate(*this);
475
    }
476
  }
477
}
478
} // namespace Fortran::semantics
479

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.