@@ -341,9 +341,136 @@ bool DummyProcedure::operator==(const DummyProcedure &that) const {
341
341
procedure.value () == that.procedure .value ();
342
342
}
343
343
344
- std::optional<DummyProcedure> DummyProcedure::Characterize (
345
- const semantics::Symbol &symbol, FoldingContext &context) {
346
- if (auto procedure{Procedure::Characterize (symbol, context)}) {
344
+ static std::string GetSeenProcs (const semantics::SymbolSet &seenProcs) {
345
+ std::string result;
346
+ llvm::interleave (
347
+ seenProcs,
348
+ [&](const SymbolRef p) { result += ' \' ' + p->name ().ToString () + ' \' ' ; },
349
+ [&]() { result += " , " ; });
350
+ return result;
351
+ }
352
+
353
+ // These functions with arguments of type SymbolSet are used with mutually
354
+ // recursive calls when characterizing a Procedure, a DummyArgument, or a
355
+ // DummyProcedure to detect circularly defined procedures as required by
356
+ // 15.4.3.6, paragraph 2.
357
+ static std::optional<DummyArgument> CharacterizeDummyArgument (
358
+ const semantics::Symbol &symbol, FoldingContext &context,
359
+ semantics::SymbolSet &seenProcs);
360
+
361
+ static std::optional<Procedure> CharacterizeProcedure (
362
+ const semantics::Symbol &original, FoldingContext &context,
363
+ semantics::SymbolSet &seenProcs) {
364
+ Procedure result;
365
+ const auto &symbol{original.GetUltimate ()};
366
+ if (seenProcs.find (symbol) != seenProcs.end ()) {
367
+ std::string procsList{GetSeenProcs (seenProcs)};
368
+ context.messages ().Say (symbol.name (),
369
+ " Procedure '%s' is recursively defined. Procedures in the cycle:"
370
+ " '%s'" _err_en_US,
371
+ symbol.name (), procsList);
372
+ return std::nullopt;
373
+ }
374
+ seenProcs.insert (symbol);
375
+ CopyAttrs<Procedure, Procedure::Attr>(symbol, result,
376
+ {
377
+ {semantics::Attr::PURE, Procedure::Attr::Pure},
378
+ {semantics::Attr::ELEMENTAL, Procedure::Attr::Elemental},
379
+ {semantics::Attr::BIND_C, Procedure::Attr::BindC},
380
+ });
381
+ if (result.attrs .test (Procedure::Attr::Elemental) &&
382
+ !symbol.attrs ().test (semantics::Attr::IMPURE)) {
383
+ result.attrs .set (Procedure::Attr::Pure); // explicitly flag pure procedures
384
+ }
385
+ return std::visit (
386
+ common::visitors{
387
+ [&](const semantics::SubprogramDetails &subp)
388
+ -> std::optional<Procedure> {
389
+ if (subp.isFunction ()) {
390
+ if (auto fr{
391
+ FunctionResult::Characterize (subp.result (), context)}) {
392
+ result.functionResult = std::move (fr);
393
+ } else {
394
+ return std::nullopt;
395
+ }
396
+ } else {
397
+ result.attrs .set (Procedure::Attr::Subroutine);
398
+ }
399
+ for (const semantics::Symbol *arg : subp.dummyArgs ()) {
400
+ if (!arg) {
401
+ result.dummyArguments .emplace_back (AlternateReturn{});
402
+ } else if (auto argCharacteristics{CharacterizeDummyArgument (
403
+ *arg, context, seenProcs)}) {
404
+ result.dummyArguments .emplace_back (
405
+ std::move (argCharacteristics.value ()));
406
+ } else {
407
+ return std::nullopt;
408
+ }
409
+ }
410
+ return result;
411
+ },
412
+ [&](const semantics::ProcEntityDetails &proc)
413
+ -> std::optional<Procedure> {
414
+ if (symbol.attrs ().test (semantics::Attr::INTRINSIC)) {
415
+ return context.intrinsics ().IsSpecificIntrinsicFunction (
416
+ symbol.name ().ToString ());
417
+ }
418
+ const semantics::ProcInterface &interface{proc.interface ()};
419
+ if (const semantics::Symbol * interfaceSymbol{interface.symbol ()}) {
420
+ return CharacterizeProcedure (
421
+ *interfaceSymbol, context, seenProcs);
422
+ } else {
423
+ result.attrs .set (Procedure::Attr::ImplicitInterface);
424
+ const semantics::DeclTypeSpec *type{interface.type ()};
425
+ if (symbol.test (semantics::Symbol::Flag::Subroutine)) {
426
+ // ignore any implicit typing
427
+ result.attrs .set (Procedure::Attr::Subroutine);
428
+ } else if (type) {
429
+ if (auto resultType{DynamicType::From (*type)}) {
430
+ result.functionResult = FunctionResult{*resultType};
431
+ } else {
432
+ return std::nullopt;
433
+ }
434
+ } else if (symbol.test (semantics::Symbol::Flag::Function)) {
435
+ return std::nullopt;
436
+ }
437
+ // The PASS name, if any, is not a characteristic.
438
+ return result;
439
+ }
440
+ },
441
+ [&](const semantics::ProcBindingDetails &binding) {
442
+ if (auto result{CharacterizeProcedure (
443
+ binding.symbol (), context, seenProcs)}) {
444
+ if (!symbol.attrs ().test (semantics::Attr::NOPASS)) {
445
+ auto passName{binding.passName ()};
446
+ for (auto &dummy : result->dummyArguments ) {
447
+ if (!passName || dummy.name .c_str () == *passName) {
448
+ dummy.pass = true ;
449
+ return result;
450
+ }
451
+ }
452
+ DIE (" PASS argument missing" );
453
+ }
454
+ return result;
455
+ } else {
456
+ return std::optional<Procedure>{};
457
+ }
458
+ },
459
+ [&](const semantics::UseDetails &use) {
460
+ return CharacterizeProcedure (use.symbol (), context, seenProcs);
461
+ },
462
+ [&](const semantics::HostAssocDetails &assoc) {
463
+ return CharacterizeProcedure (assoc.symbol (), context, seenProcs);
464
+ },
465
+ [](const auto &) { return std::optional<Procedure>{}; },
466
+ },
467
+ symbol.details ());
468
+ }
469
+
470
+ static std::optional<DummyProcedure> CharacterizeDummyProcedure (
471
+ const semantics::Symbol &symbol, FoldingContext &context,
472
+ semantics::SymbolSet &seenProcs) {
473
+ if (auto procedure{CharacterizeProcedure (symbol, context, seenProcs)}) {
347
474
// Dummy procedures may not be elemental. Elemental dummy procedure
348
475
// interfaces are errors when the interface is not intrinsic, and that
349
476
// error is caught elsewhere. Elemental intrinsic interfaces are
@@ -381,14 +508,16 @@ bool DummyArgument::operator==(const DummyArgument &that) const {
381
508
return u == that.u ; // name and passed-object usage are not characteristics
382
509
}
383
510
384
- std::optional<DummyArgument> DummyArgument::Characterize (
385
- const semantics::Symbol &symbol, FoldingContext &context) {
511
+ static std::optional<DummyArgument> CharacterizeDummyArgument (
512
+ const semantics::Symbol &symbol, FoldingContext &context,
513
+ semantics::SymbolSet &seenProcs) {
386
514
auto name{symbol.name ().ToString ()};
387
515
if (symbol.has <semantics::ObjectEntityDetails>()) {
388
516
if (auto obj{DummyDataObject::Characterize (symbol, context)}) {
389
517
return DummyArgument{std::move (name), std::move (obj.value ())};
390
518
}
391
- } else if (auto proc{DummyProcedure::Characterize (symbol, context)}) {
519
+ } else if (auto proc{
520
+ CharacterizeDummyProcedure (symbol, context, seenProcs)}) {
392
521
return DummyArgument{std::move (name), std::move (proc.value ())};
393
522
}
394
523
return std::nullopt;
@@ -644,99 +773,8 @@ bool Procedure::CanOverride(
644
773
645
774
std::optional<Procedure> Procedure::Characterize (
646
775
const semantics::Symbol &original, FoldingContext &context) {
647
- Procedure result;
648
- const auto &symbol{original.GetUltimate ()};
649
- CopyAttrs<Procedure, Procedure::Attr>(symbol, result,
650
- {
651
- {semantics::Attr::PURE, Procedure::Attr::Pure},
652
- {semantics::Attr::ELEMENTAL, Procedure::Attr::Elemental},
653
- {semantics::Attr::BIND_C, Procedure::Attr::BindC},
654
- });
655
- if (result.attrs .test (Attr::Elemental) &&
656
- !symbol.attrs ().test (semantics::Attr::IMPURE)) {
657
- result.attrs .set (Attr::Pure); // explicitly flag pure procedures
658
- }
659
- return std::visit (
660
- common::visitors{
661
- [&](const semantics::SubprogramDetails &subp)
662
- -> std::optional<Procedure> {
663
- if (subp.isFunction ()) {
664
- if (auto fr{
665
- FunctionResult::Characterize (subp.result (), context)}) {
666
- result.functionResult = std::move (fr);
667
- } else {
668
- return std::nullopt;
669
- }
670
- } else {
671
- result.attrs .set (Attr::Subroutine);
672
- }
673
- for (const semantics::Symbol *arg : subp.dummyArgs ()) {
674
- if (!arg) {
675
- result.dummyArguments .emplace_back (AlternateReturn{});
676
- } else if (auto argCharacteristics{
677
- DummyArgument::Characterize (*arg, context)}) {
678
- result.dummyArguments .emplace_back (
679
- std::move (argCharacteristics.value ()));
680
- } else {
681
- return std::nullopt;
682
- }
683
- }
684
- return result;
685
- },
686
- [&](const semantics::ProcEntityDetails &proc)
687
- -> std::optional<Procedure> {
688
- if (symbol.attrs ().test (semantics::Attr::INTRINSIC)) {
689
- return context.intrinsics ().IsSpecificIntrinsicFunction (
690
- symbol.name ().ToString ());
691
- }
692
- const semantics::ProcInterface &interface{proc.interface ()};
693
- if (const semantics::Symbol * interfaceSymbol{interface.symbol ()}) {
694
- return Characterize (*interfaceSymbol, context);
695
- } else {
696
- result.attrs .set (Attr::ImplicitInterface);
697
- const semantics::DeclTypeSpec *type{interface.type ()};
698
- if (symbol.test (semantics::Symbol::Flag::Subroutine)) {
699
- // ignore any implicit typing
700
- result.attrs .set (Attr::Subroutine);
701
- } else if (type) {
702
- if (auto resultType{DynamicType::From (*type)}) {
703
- result.functionResult = FunctionResult{*resultType};
704
- } else {
705
- return std::nullopt;
706
- }
707
- } else if (symbol.test (semantics::Symbol::Flag::Function)) {
708
- return std::nullopt;
709
- }
710
- // The PASS name, if any, is not a characteristic.
711
- return result;
712
- }
713
- },
714
- [&](const semantics::ProcBindingDetails &binding) {
715
- if (auto result{Characterize (binding.symbol (), context)}) {
716
- if (!symbol.attrs ().test (semantics::Attr::NOPASS)) {
717
- auto passName{binding.passName ()};
718
- for (auto &dummy : result->dummyArguments ) {
719
- if (!passName || dummy.name .c_str () == *passName) {
720
- dummy.pass = true ;
721
- return result;
722
- }
723
- }
724
- DIE (" PASS argument missing" );
725
- }
726
- return result;
727
- } else {
728
- return std::optional<Procedure>{};
729
- }
730
- },
731
- [&](const semantics::UseDetails &use) {
732
- return Characterize (use.symbol (), context);
733
- },
734
- [&](const semantics::HostAssocDetails &assoc) {
735
- return Characterize (assoc.symbol (), context);
736
- },
737
- [](const auto &) { return std::optional<Procedure>{}; },
738
- },
739
- symbol.details ());
776
+ semantics::SymbolSet seenProcs;
777
+ return CharacterizeProcedure (original, context, seenProcs);
740
778
}
741
779
742
780
std::optional<Procedure> Procedure::Characterize (
0 commit comments