llvm-project

Форк
0
862 строки · 25.5 Кб
1
//===-- lib/Semantics/symbol.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/symbol.h"
10
#include "flang/Common/idioms.h"
11
#include "flang/Evaluate/expression.h"
12
#include "flang/Semantics/scope.h"
13
#include "flang/Semantics/semantics.h"
14
#include "flang/Semantics/tools.h"
15
#include "llvm/Support/raw_ostream.h"
16
#include <cstring>
17
#include <string>
18
#include <type_traits>
19

20
namespace Fortran::semantics {
21

22
template <typename T>
23
static void DumpOptional(llvm::raw_ostream &os, const char *label, const T &x) {
24
  if (x) {
25
    os << ' ' << label << ':' << *x;
26
  }
27
}
28
template <typename T>
29
static void DumpExpr(llvm::raw_ostream &os, const char *label,
30
    const std::optional<evaluate::Expr<T>> &x) {
31
  if (x) {
32
    x->AsFortran(os << ' ' << label << ':');
33
  }
34
}
35

36
static void DumpBool(llvm::raw_ostream &os, const char *label, bool x) {
37
  if (x) {
38
    os << ' ' << label;
39
  }
40
}
41

42
static void DumpSymbolVector(llvm::raw_ostream &os, const SymbolVector &list) {
43
  char sep{' '};
44
  for (const Symbol &elem : list) {
45
    os << sep << elem.name();
46
    sep = ',';
47
  }
48
}
49

50
static void DumpType(llvm::raw_ostream &os, const Symbol &symbol) {
51
  if (const auto *type{symbol.GetType()}) {
52
    os << *type << ' ';
53
  }
54
}
55
static void DumpType(llvm::raw_ostream &os, const DeclTypeSpec *type) {
56
  if (type) {
57
    os << ' ' << *type;
58
  }
59
}
60

61
template <typename T>
62
static void DumpList(llvm::raw_ostream &os, const char *label, const T &list) {
63
  if (!list.empty()) {
64
    os << ' ' << label << ':';
65
    char sep{' '};
66
    for (const auto &elem : list) {
67
      os << sep << elem;
68
      sep = ',';
69
    }
70
  }
71
}
72

73
void SubprogramDetails::set_moduleInterface(Symbol &symbol) {
74
  CHECK(!moduleInterface_);
75
  moduleInterface_ = &symbol;
76
}
77

78
const Scope *ModuleDetails::parent() const {
79
  return isSubmodule_ && scope_ ? &scope_->parent() : nullptr;
80
}
81
const Scope *ModuleDetails::ancestor() const {
82
  return isSubmodule_ && scope_ ? FindModuleContaining(*scope_) : nullptr;
83
}
84
void ModuleDetails::set_scope(const Scope *scope) {
85
  CHECK(!scope_);
86
  bool scopeIsSubmodule{scope->parent().kind() == Scope::Kind::Module};
87
  CHECK(isSubmodule_ == scopeIsSubmodule);
88
  scope_ = scope;
89
}
90

91
llvm::raw_ostream &operator<<(
92
    llvm::raw_ostream &os, const SubprogramDetails &x) {
93
  DumpBool(os, "isInterface", x.isInterface_);
94
  DumpBool(os, "dummy", x.isDummy_);
95
  DumpOptional(os, "bindName", x.bindName());
96
  if (x.result_) {
97
    DumpType(os << " result:", x.result());
98
    os << x.result_->name();
99
    if (!x.result_->attrs().empty()) {
100
      os << ", " << x.result_->attrs();
101
    }
102
  }
103
  if (x.entryScope_) {
104
    os << " entry";
105
    if (x.entryScope_->symbol()) {
106
      os << " in " << x.entryScope_->symbol()->name();
107
    }
108
  }
109
  char sep{'('};
110
  os << ' ';
111
  for (const Symbol *arg : x.dummyArgs_) {
112
    os << sep;
113
    sep = ',';
114
    if (arg) {
115
      DumpType(os, *arg);
116
      os << arg->name();
117
    } else {
118
      os << '*';
119
    }
120
  }
121
  os << (sep == '(' ? "()" : ")");
122
  if (x.stmtFunction_) {
123
    os << " -> " << x.stmtFunction_->AsFortran();
124
  }
125
  if (x.moduleInterface_) {
126
    os << " moduleInterface: " << *x.moduleInterface_;
127
  }
128
  if (x.defaultIgnoreTKR_) {
129
    os << " defaultIgnoreTKR";
130
  }
131
  if (x.cudaSubprogramAttrs_) {
132
    os << " cudaSubprogramAttrs: "
133
       << common::EnumToString(*x.cudaSubprogramAttrs_);
134
  }
135
  if (!x.cudaLaunchBounds_.empty()) {
136
    os << " cudaLaunchBounds:";
137
    for (auto x : x.cudaLaunchBounds_) {
138
      os << ' ' << x;
139
    }
140
  }
141
  if (!x.cudaClusterDims_.empty()) {
142
    os << " cudaClusterDims:";
143
    for (auto x : x.cudaClusterDims_) {
144
      os << ' ' << x;
145
    }
146
  }
147
  return os;
148
}
149

150
void EntityDetails::set_type(const DeclTypeSpec &type) {
151
  CHECK(!type_);
152
  type_ = &type;
153
}
154

155
void AssocEntityDetails::set_rank(int rank) { rank_ = rank; }
156
void AssocEntityDetails::set_IsAssumedSize() { rank_ = isAssumedSize; }
157
void AssocEntityDetails::set_IsAssumedRank() { rank_ = isAssumedRank; }
158
void EntityDetails::ReplaceType(const DeclTypeSpec &type) { type_ = &type; }
159

160
ObjectEntityDetails::ObjectEntityDetails(EntityDetails &&d)
161
    : EntityDetails(std::move(d)) {}
162

163
void ObjectEntityDetails::set_shape(const ArraySpec &shape) {
164
  CHECK(shape_.empty());
165
  for (const auto &shapeSpec : shape) {
166
    shape_.push_back(shapeSpec);
167
  }
168
}
169
void ObjectEntityDetails::set_coshape(const ArraySpec &coshape) {
170
  CHECK(coshape_.empty());
171
  for (const auto &shapeSpec : coshape) {
172
    coshape_.push_back(shapeSpec);
173
  }
174
}
175

176
ProcEntityDetails::ProcEntityDetails(EntityDetails &&d)
177
    : EntityDetails(std::move(d)) {}
178

179
UseErrorDetails::UseErrorDetails(const UseDetails &useDetails) {
180
  add_occurrence(useDetails.location(), *GetUsedModule(useDetails).scope());
181
}
182
UseErrorDetails &UseErrorDetails::add_occurrence(
183
    const SourceName &location, const Scope &module) {
184
  occurrences_.push_back(std::make_pair(location, &module));
185
  return *this;
186
}
187

188
void GenericDetails::AddSpecificProc(
189
    const Symbol &proc, SourceName bindingName) {
190
  specificProcs_.push_back(proc);
191
  bindingNames_.push_back(bindingName);
192
}
193
void GenericDetails::set_specific(Symbol &specific) {
194
  CHECK(!specific_);
195
  specific_ = &specific;
196
}
197
void GenericDetails::clear_specific() { specific_ = nullptr; }
198
void GenericDetails::set_derivedType(Symbol &derivedType) {
199
  CHECK(!derivedType_);
200
  derivedType_ = &derivedType;
201
}
202
void GenericDetails::clear_derivedType() { derivedType_ = nullptr; }
203
void GenericDetails::AddUse(const Symbol &use) {
204
  CHECK(use.has<UseDetails>());
205
  uses_.push_back(use);
206
}
207

208
const Symbol *GenericDetails::CheckSpecific() const {
209
  return const_cast<GenericDetails *>(this)->CheckSpecific();
210
}
211
Symbol *GenericDetails::CheckSpecific() {
212
  if (specific_ && !specific_->has<UseErrorDetails>()) {
213
    for (const Symbol &proc : specificProcs_) {
214
      if (&proc == specific_) {
215
        return nullptr;
216
      }
217
    }
218
    return specific_;
219
  } else {
220
    return nullptr;
221
  }
222
}
223

224
void GenericDetails::CopyFrom(const GenericDetails &from) {
225
  CHECK(specificProcs_.size() == bindingNames_.size());
226
  CHECK(from.specificProcs_.size() == from.bindingNames_.size());
227
  kind_ = from.kind_;
228
  if (from.derivedType_) {
229
    CHECK(!derivedType_ || derivedType_ == from.derivedType_);
230
    derivedType_ = from.derivedType_;
231
  }
232
  for (std::size_t i{0}; i < from.specificProcs_.size(); ++i) {
233
    if (std::find_if(specificProcs_.begin(), specificProcs_.end(),
234
            [&](const Symbol &mySymbol) {
235
              return &mySymbol.GetUltimate() ==
236
                  &from.specificProcs_[i]->GetUltimate();
237
            }) == specificProcs_.end()) {
238
      specificProcs_.push_back(from.specificProcs_[i]);
239
      bindingNames_.push_back(from.bindingNames_[i]);
240
    }
241
  }
242
}
243

244
// The name of the kind of details for this symbol.
245
// This is primarily for debugging.
246
std::string DetailsToString(const Details &details) {
247
  return common::visit(
248
      common::visitors{
249
          [](const UnknownDetails &) { return "Unknown"; },
250
          [](const MainProgramDetails &) { return "MainProgram"; },
251
          [](const ModuleDetails &) { return "Module"; },
252
          [](const SubprogramDetails &) { return "Subprogram"; },
253
          [](const SubprogramNameDetails &) { return "SubprogramName"; },
254
          [](const EntityDetails &) { return "Entity"; },
255
          [](const ObjectEntityDetails &) { return "ObjectEntity"; },
256
          [](const ProcEntityDetails &) { return "ProcEntity"; },
257
          [](const DerivedTypeDetails &) { return "DerivedType"; },
258
          [](const UseDetails &) { return "Use"; },
259
          [](const UseErrorDetails &) { return "UseError"; },
260
          [](const HostAssocDetails &) { return "HostAssoc"; },
261
          [](const GenericDetails &) { return "Generic"; },
262
          [](const ProcBindingDetails &) { return "ProcBinding"; },
263
          [](const NamelistDetails &) { return "Namelist"; },
264
          [](const CommonBlockDetails &) { return "CommonBlockDetails"; },
265
          [](const TypeParamDetails &) { return "TypeParam"; },
266
          [](const MiscDetails &) { return "Misc"; },
267
          [](const AssocEntityDetails &) { return "AssocEntity"; },
268
      },
269
      details);
270
}
271

272
std::string Symbol::GetDetailsName() const { return DetailsToString(details_); }
273

274
void Symbol::set_details(Details &&details) {
275
  CHECK(CanReplaceDetails(details));
276
  details_ = std::move(details);
277
}
278

279
bool Symbol::CanReplaceDetails(const Details &details) const {
280
  if (has<UnknownDetails>()) {
281
    return true; // can always replace UnknownDetails
282
  } else {
283
    return common::visit(
284
        common::visitors{
285
            [](const UseErrorDetails &) { return true; },
286
            [&](const ObjectEntityDetails &) { return has<EntityDetails>(); },
287
            [&](const ProcEntityDetails &) { return has<EntityDetails>(); },
288
            [&](const SubprogramDetails &) {
289
              return has<SubprogramNameDetails>() || has<EntityDetails>();
290
            },
291
            [&](const DerivedTypeDetails &) {
292
              const auto *derived{this->detailsIf<DerivedTypeDetails>()};
293
              return derived && derived->isForwardReferenced();
294
            },
295
            [&](const UseDetails &x) {
296
              const auto *use{this->detailsIf<UseDetails>()};
297
              return use && use->symbol() == x.symbol();
298
            },
299
            [&](const HostAssocDetails &) {
300
              return this->has<HostAssocDetails>();
301
            },
302
            [](const auto &) { return false; },
303
        },
304
        details);
305
  }
306
}
307

308
// Usually a symbol's name is the first occurrence in the source, but sometimes
309
// we want to replace it with one at a different location (but same characters).
310
void Symbol::ReplaceName(const SourceName &name) {
311
  CHECK(name == name_);
312
  name_ = name;
313
}
314

315
void Symbol::SetType(const DeclTypeSpec &type) {
316
  common::visit(common::visitors{
317
                    [&](EntityDetails &x) { x.set_type(type); },
318
                    [&](ObjectEntityDetails &x) { x.set_type(type); },
319
                    [&](AssocEntityDetails &x) { x.set_type(type); },
320
                    [&](ProcEntityDetails &x) { x.set_type(type); },
321
                    [&](TypeParamDetails &x) { x.set_type(type); },
322
                    [](auto &) {},
323
                },
324
      details_);
325
}
326

327
template <typename T>
328
constexpr bool HasBindName{std::is_convertible_v<T, const WithBindName *>};
329

330
const std::string *Symbol::GetBindName() const {
331
  return common::visit(
332
      [&](auto &x) -> const std::string * {
333
        if constexpr (HasBindName<decltype(&x)>) {
334
          return x.bindName();
335
        } else {
336
          return nullptr;
337
        }
338
      },
339
      details_);
340
}
341

342
void Symbol::SetBindName(std::string &&name) {
343
  common::visit(
344
      [&](auto &x) {
345
        if constexpr (HasBindName<decltype(&x)>) {
346
          x.set_bindName(std::move(name));
347
        } else {
348
          DIE("bind name not allowed on this kind of symbol");
349
        }
350
      },
351
      details_);
352
}
353

354
bool Symbol::GetIsExplicitBindName() const {
355
  return common::visit(
356
      [&](auto &x) -> bool {
357
        if constexpr (HasBindName<decltype(&x)>) {
358
          return x.isExplicitBindName();
359
        } else {
360
          return false;
361
        }
362
      },
363
      details_);
364
}
365

366
void Symbol::SetIsExplicitBindName(bool yes) {
367
  common::visit(
368
      [&](auto &x) {
369
        if constexpr (HasBindName<decltype(&x)>) {
370
          x.set_isExplicitBindName(yes);
371
        } else {
372
          DIE("bind name not allowed on this kind of symbol");
373
        }
374
      },
375
      details_);
376
}
377

378
void Symbol::SetIsCDefined(bool yes) {
379
  common::visit(
380
      [&](auto &x) {
381
        if constexpr (HasBindName<decltype(&x)>) {
382
          x.set_isCDefined(yes);
383
        } else {
384
          DIE("CDEFINED not allowed on this kind of symbol");
385
        }
386
      },
387
      details_);
388
}
389

390
bool Symbol::IsFuncResult() const {
391
  return common::visit(
392
      common::visitors{[](const EntityDetails &x) { return x.isFuncResult(); },
393
          [](const ObjectEntityDetails &x) { return x.isFuncResult(); },
394
          [](const ProcEntityDetails &x) { return x.isFuncResult(); },
395
          [](const HostAssocDetails &x) { return x.symbol().IsFuncResult(); },
396
          [](const auto &) { return false; }},
397
      details_);
398
}
399

400
const ArraySpec *Symbol::GetShape() const {
401
  if (const auto *details{std::get_if<ObjectEntityDetails>(&details_)}) {
402
    return &details->shape();
403
  } else {
404
    return nullptr;
405
  }
406
}
407

408
bool Symbol::IsObjectArray() const {
409
  const ArraySpec *shape{GetShape()};
410
  return shape && !shape->empty();
411
}
412

413
bool Symbol::IsSubprogram() const {
414
  return common::visit(
415
      common::visitors{
416
          [](const SubprogramDetails &) { return true; },
417
          [](const SubprogramNameDetails &) { return true; },
418
          [](const GenericDetails &) { return true; },
419
          [](const UseDetails &x) { return x.symbol().IsSubprogram(); },
420
          [](const auto &) { return false; },
421
      },
422
      details_);
423
}
424

425
bool Symbol::IsFromModFile() const {
426
  return test(Flag::ModFile) ||
427
      (!owner_->IsTopLevel() && owner_->symbol()->IsFromModFile());
428
}
429

430
llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const EntityDetails &x) {
431
  DumpBool(os, "dummy", x.isDummy());
432
  DumpBool(os, "funcResult", x.isFuncResult());
433
  if (x.type()) {
434
    os << " type: " << *x.type();
435
  }
436
  DumpOptional(os, "bindName", x.bindName());
437
  DumpBool(os, "CDEFINED", x.isCDefined());
438
  return os;
439
}
440

441
llvm::raw_ostream &operator<<(
442
    llvm::raw_ostream &os, const ObjectEntityDetails &x) {
443
  os << *static_cast<const EntityDetails *>(&x);
444
  DumpList(os, "shape", x.shape());
445
  DumpList(os, "coshape", x.coshape());
446
  DumpExpr(os, "init", x.init_);
447
  if (x.unanalyzedPDTComponentInit()) {
448
    os << " (has unanalyzedPDTComponentInit)";
449
  }
450
  if (!x.ignoreTKR_.empty()) {
451
    x.ignoreTKR_.Dump(os << ' ', common::EnumToString);
452
  }
453
  if (x.cudaDataAttr()) {
454
    os << " cudaDataAttr: " << common::EnumToString(*x.cudaDataAttr());
455
  }
456
  return os;
457
}
458

459
llvm::raw_ostream &operator<<(
460
    llvm::raw_ostream &os, const AssocEntityDetails &x) {
461
  os << *static_cast<const EntityDetails *>(&x);
462
  if (x.IsAssumedSize()) {
463
    os << " RANK(*)";
464
  } else if (x.IsAssumedRank()) {
465
    os << " RANK DEFAULT";
466
  } else if (auto assocRank{x.rank()}) {
467
    os << " RANK(" << *assocRank << ')';
468
  }
469
  DumpExpr(os, "expr", x.expr());
470
  return os;
471
}
472

473
llvm::raw_ostream &operator<<(
474
    llvm::raw_ostream &os, const ProcEntityDetails &x) {
475
  if (x.procInterface_) {
476
    if (x.rawProcInterface_ != x.procInterface_) {
477
      os << ' ' << x.rawProcInterface_->name() << " ->";
478
    }
479
    os << ' ' << x.procInterface_->name();
480
  } else {
481
    DumpType(os, x.type());
482
  }
483
  DumpOptional(os, "bindName", x.bindName());
484
  DumpOptional(os, "passName", x.passName());
485
  if (x.init()) {
486
    if (const Symbol * target{*x.init()}) {
487
      os << " => " << target->name();
488
    } else {
489
      os << " => NULL()";
490
    }
491
  }
492
  if (x.isCUDAKernel()) {
493
    os << " isCUDAKernel";
494
  }
495
  return os;
496
}
497

498
llvm::raw_ostream &operator<<(
499
    llvm::raw_ostream &os, const DerivedTypeDetails &x) {
500
  DumpBool(os, "sequence", x.sequence_);
501
  DumpList(os, "components", x.componentNames_);
502
  return os;
503
}
504

505
llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const GenericDetails &x) {
506
  os << ' ' << x.kind().ToString();
507
  DumpBool(os, "(specific)", x.specific() != nullptr);
508
  DumpBool(os, "(derivedType)", x.derivedType() != nullptr);
509
  if (const auto &uses{x.uses()}; !uses.empty()) {
510
    os << " (uses:";
511
    char sep{' '};
512
    for (const Symbol &use : uses) {
513
      const Symbol &ultimate{use.GetUltimate()};
514
      os << sep << ultimate.name() << "->"
515
         << ultimate.owner().GetName().value();
516
      sep = ',';
517
    }
518
    os << ')';
519
  }
520
  os << " procs:";
521
  DumpSymbolVector(os, x.specificProcs());
522
  return os;
523
}
524

525
llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Details &details) {
526
  os << DetailsToString(details);
527
  common::visit( //
528
      common::visitors{
529
          [&](const UnknownDetails &) {},
530
          [&](const MainProgramDetails &) {},
531
          [&](const ModuleDetails &x) {
532
            if (x.isSubmodule()) {
533
              os << " (";
534
              if (x.ancestor()) {
535
                auto ancestor{x.ancestor()->GetName().value()};
536
                os << ancestor;
537
                if (x.parent()) {
538
                  auto parent{x.parent()->GetName().value()};
539
                  if (ancestor != parent) {
540
                    os << ':' << parent;
541
                  }
542
                }
543
              }
544
              os << ")";
545
            }
546
            if (x.isDefaultPrivate()) {
547
              os << " isDefaultPrivate";
548
            }
549
          },
550
          [&](const SubprogramNameDetails &x) {
551
            os << ' ' << EnumToString(x.kind());
552
          },
553
          [&](const UseDetails &x) {
554
            os << " from " << x.symbol().name() << " in "
555
               << GetUsedModule(x).name();
556
          },
557
          [&](const UseErrorDetails &x) {
558
            os << " uses:";
559
            char sep{':'};
560
            for (const auto &[location, module] : x.occurrences()) {
561
              os << sep << " from " << module->GetName().value() << " at "
562
                 << location;
563
              sep = ',';
564
            }
565
          },
566
          [](const HostAssocDetails &) {},
567
          [&](const ProcBindingDetails &x) {
568
            os << " => " << x.symbol().name();
569
            DumpOptional(os, "passName", x.passName());
570
            if (x.numPrivatesNotOverridden() > 0) {
571
              os << " numPrivatesNotOverridden: "
572
                 << x.numPrivatesNotOverridden();
573
            }
574
          },
575
          [&](const NamelistDetails &x) {
576
            os << ':';
577
            DumpSymbolVector(os, x.objects());
578
          },
579
          [&](const CommonBlockDetails &x) {
580
            DumpOptional(os, "bindName", x.bindName());
581
            if (x.alignment()) {
582
              os << " alignment=" << x.alignment();
583
            }
584
            os << ':';
585
            for (const auto &object : x.objects()) {
586
              os << ' ' << object->name();
587
            }
588
          },
589
          [&](const TypeParamDetails &x) {
590
            DumpOptional(os, "type", x.type());
591
            os << ' ' << common::EnumToString(x.attr());
592
            DumpExpr(os, "init", x.init());
593
          },
594
          [&](const MiscDetails &x) {
595
            os << ' ' << MiscDetails::EnumToString(x.kind());
596
          },
597
          [&](const auto &x) { os << x; },
598
      },
599
      details);
600
  return os;
601
}
602

603
llvm::raw_ostream &operator<<(llvm::raw_ostream &o, Symbol::Flag flag) {
604
  return o << Symbol::EnumToString(flag);
605
}
606

607
llvm::raw_ostream &operator<<(
608
    llvm::raw_ostream &o, const Symbol::Flags &flags) {
609
  std::size_t n{flags.count()};
610
  std::size_t seen{0};
611
  for (std::size_t j{0}; seen < n; ++j) {
612
    Symbol::Flag flag{static_cast<Symbol::Flag>(j)};
613
    if (flags.test(flag)) {
614
      if (seen++ > 0) {
615
        o << ", ";
616
      }
617
      o << flag;
618
    }
619
  }
620
  return o;
621
}
622

623
llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Symbol &symbol) {
624
  os << symbol.name();
625
  if (!symbol.attrs().empty()) {
626
    os << ", " << symbol.attrs();
627
  }
628
  if (!symbol.flags().empty()) {
629
    os << " (" << symbol.flags() << ')';
630
  }
631
  if (symbol.size_) {
632
    os << " size=" << symbol.size_ << " offset=" << symbol.offset_;
633
  }
634
  os << ": " << symbol.details_;
635
  return os;
636
}
637

638
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
639
void Symbol::dump() const { llvm::errs() << *this << '\n'; }
640
#endif
641

642
// Output a unique name for a scope by qualifying it with the names of
643
// parent scopes. For scopes without corresponding symbols, use the kind
644
// with an index (e.g. Block1, Block2, etc.).
645
static void DumpUniqueName(llvm::raw_ostream &os, const Scope &scope) {
646
  if (!scope.IsTopLevel()) {
647
    DumpUniqueName(os, scope.parent());
648
    os << '/';
649
    if (auto *scopeSymbol{scope.symbol()};
650
        scopeSymbol && !scopeSymbol->name().empty()) {
651
      os << scopeSymbol->name();
652
    } else {
653
      int index{1};
654
      for (auto &child : scope.parent().children()) {
655
        if (child == scope) {
656
          break;
657
        }
658
        if (child.kind() == scope.kind()) {
659
          ++index;
660
        }
661
      }
662
      os << Scope::EnumToString(scope.kind()) << index;
663
    }
664
  }
665
}
666

667
// Dump a symbol for UnparseWithSymbols. This will be used for tests so the
668
// format should be reasonably stable.
669
llvm::raw_ostream &DumpForUnparse(
670
    llvm::raw_ostream &os, const Symbol &symbol, bool isDef) {
671
  DumpUniqueName(os, symbol.owner());
672
  os << '/' << symbol.name();
673
  if (isDef) {
674
    if (!symbol.attrs().empty()) {
675
      os << ' ' << symbol.attrs();
676
    }
677
    if (!symbol.flags().empty()) {
678
      os << " (" << symbol.flags() << ')';
679
    }
680
    os << ' ' << symbol.GetDetailsName();
681
    DumpType(os, symbol.GetType());
682
  }
683
  return os;
684
}
685

686
const DerivedTypeSpec *Symbol::GetParentTypeSpec(const Scope *scope) const {
687
  if (const Symbol * parentComponent{GetParentComponent(scope)}) {
688
    const auto &object{parentComponent->get<ObjectEntityDetails>()};
689
    return &object.type()->derivedTypeSpec();
690
  } else {
691
    return nullptr;
692
  }
693
}
694

695
const Symbol *Symbol::GetParentComponent(const Scope *scope) const {
696
  if (const auto *dtDetails{detailsIf<DerivedTypeDetails>()}) {
697
    if (const Scope * localScope{scope ? scope : scope_}) {
698
      return dtDetails->GetParentComponent(DEREF(localScope));
699
    }
700
  }
701
  return nullptr;
702
}
703

704
void DerivedTypeDetails::add_component(const Symbol &symbol) {
705
  if (symbol.test(Symbol::Flag::ParentComp)) {
706
    CHECK(componentNames_.empty());
707
  }
708
  componentNames_.push_back(symbol.name());
709
}
710

711
const Symbol *DerivedTypeDetails::GetParentComponent(const Scope &scope) const {
712
  if (auto extends{GetParentComponentName()}) {
713
    if (auto iter{scope.find(*extends)}; iter != scope.cend()) {
714
      if (const Symbol & symbol{*iter->second};
715
          symbol.test(Symbol::Flag::ParentComp)) {
716
        return &symbol;
717
      }
718
    }
719
  }
720
  return nullptr;
721
}
722

723
const Symbol *DerivedTypeDetails::GetFinalForRank(int rank) const {
724
  for (const auto &pair : finals_) {
725
    const Symbol &symbol{*pair.second};
726
    if (const auto *details{symbol.detailsIf<SubprogramDetails>()}) {
727
      if (details->dummyArgs().size() == 1) {
728
        if (const Symbol * arg{details->dummyArgs().at(0)}) {
729
          if (const auto *object{arg->detailsIf<ObjectEntityDetails>()}) {
730
            if (rank == object->shape().Rank() || object->IsAssumedRank() ||
731
                IsElementalProcedure(symbol)) {
732
              return &symbol;
733
            }
734
          }
735
        }
736
      }
737
    }
738
  }
739
  return nullptr;
740
}
741

742
void TypeParamDetails::set_type(const DeclTypeSpec &type) {
743
  CHECK(!type_);
744
  type_ = &type;
745
}
746

747
bool GenericKind::IsIntrinsicOperator() const {
748
  return Is(OtherKind::Concat) || Has<common::LogicalOperator>() ||
749
      Has<common::NumericOperator>() || Has<common::RelationalOperator>();
750
}
751

752
bool GenericKind::IsOperator() const {
753
  return IsDefinedOperator() || IsIntrinsicOperator();
754
}
755

756
std::string GenericKind::ToString() const {
757
  return common::visit(
758
      common::visitors{
759
          [](const OtherKind &x) { return std::string{EnumToString(x)}; },
760
          [](const common::DefinedIo &x) { return AsFortran(x).ToString(); },
761
          [](const auto &x) { return std::string{common::EnumToString(x)}; },
762
      },
763
      u);
764
}
765

766
SourceName GenericKind::AsFortran(common::DefinedIo x) {
767
  const char *name{common::AsFortran(x)};
768
  return {name, std::strlen(name)};
769
}
770

771
bool GenericKind::Is(GenericKind::OtherKind x) const {
772
  const OtherKind *y{std::get_if<OtherKind>(&u)};
773
  return y && *y == x;
774
}
775

776
std::string Symbol::OmpFlagToClauseName(Symbol::Flag ompFlag) {
777
  std::string clauseName;
778
  switch (ompFlag) {
779
  case Symbol::Flag::OmpShared:
780
    clauseName = "SHARED";
781
    break;
782
  case Symbol::Flag::OmpPrivate:
783
    clauseName = "PRIVATE";
784
    break;
785
  case Symbol::Flag::OmpLinear:
786
    clauseName = "LINEAR";
787
    break;
788
  case Symbol::Flag::OmpFirstPrivate:
789
    clauseName = "FIRSTPRIVATE";
790
    break;
791
  case Symbol::Flag::OmpLastPrivate:
792
    clauseName = "LASTPRIVATE";
793
    break;
794
  case Symbol::Flag::OmpMapTo:
795
  case Symbol::Flag::OmpMapFrom:
796
  case Symbol::Flag::OmpMapToFrom:
797
  case Symbol::Flag::OmpMapAlloc:
798
  case Symbol::Flag::OmpMapRelease:
799
  case Symbol::Flag::OmpMapDelete:
800
    clauseName = "MAP";
801
    break;
802
  case Symbol::Flag::OmpUseDevicePtr:
803
    clauseName = "USE_DEVICE_PTR";
804
    break;
805
  case Symbol::Flag::OmpUseDeviceAddr:
806
    clauseName = "USE_DEVICE_ADDR";
807
    break;
808
  case Symbol::Flag::OmpCopyIn:
809
    clauseName = "COPYIN";
810
    break;
811
  case Symbol::Flag::OmpCopyPrivate:
812
    clauseName = "COPYPRIVATE";
813
    break;
814
  case Symbol::Flag::OmpIsDevicePtr:
815
    clauseName = "IS_DEVICE_PTR";
816
    break;
817
  case Symbol::Flag::OmpHasDeviceAddr:
818
    clauseName = "HAS_DEVICE_ADDR";
819
    break;
820
  default:
821
    clauseName = "";
822
    break;
823
  }
824
  return clauseName;
825
}
826

827
bool SymbolOffsetCompare::operator()(
828
    const SymbolRef &x, const SymbolRef &y) const {
829
  const Symbol *xCommon{FindCommonBlockContaining(*x)};
830
  const Symbol *yCommon{FindCommonBlockContaining(*y)};
831
  if (xCommon) {
832
    if (yCommon) {
833
      const SymbolSourcePositionCompare sourceCmp;
834
      if (sourceCmp(*xCommon, *yCommon)) {
835
        return true;
836
      } else if (sourceCmp(*yCommon, *xCommon)) {
837
        return false;
838
      } else if (x->offset() == y->offset()) {
839
        return x->size() > y->size();
840
      } else {
841
        return x->offset() < y->offset();
842
      }
843
    } else {
844
      return false;
845
    }
846
  } else if (yCommon) {
847
    return true;
848
  } else if (x->offset() == y->offset()) {
849
    return x->size() > y->size();
850
  } else {
851
    return x->offset() < y->offset();
852
  }
853
  return x->GetSemanticsContext().allCookedSources().Precedes(
854
      x->name(), y->name());
855
}
856

857
bool SymbolOffsetCompare::operator()(
858
    const MutableSymbolRef &x, const MutableSymbolRef &y) const {
859
  return (*this)(SymbolRef{*x}, SymbolRef{*y});
860
}
861

862
} // namespace Fortran::semantics
863

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

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

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

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