1 | //===-- lib/Semantics/check-deallocate.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 "check-deallocate.h" |
10 | #include "definable.h" |
11 | #include "flang/Evaluate/type.h" |
12 | #include "flang/Parser/message.h" |
13 | #include "flang/Parser/parse-tree.h" |
14 | #include "flang/Semantics/expression.h" |
15 | #include "flang/Semantics/tools.h" |
16 | |
17 | namespace Fortran::semantics { |
18 | |
19 | void DeallocateChecker::Leave(const parser::DeallocateStmt &deallocateStmt) { |
20 | for (const parser::AllocateObject &allocateObject : |
21 | std::get<std::list<parser::AllocateObject>>(deallocateStmt.t)) { |
22 | common::visit( |
23 | common::visitors{ |
24 | [&](const parser::Name &name) { |
25 | const Symbol *symbol{ |
26 | name.symbol ? &name.symbol->GetUltimate() : nullptr}; |
27 | ; |
28 | if (context_.HasError(symbol)) { |
29 | // already reported an error |
30 | } else if (!IsVariableName(*symbol)) { |
31 | context_.Say(name.source, |
32 | "Name in DEALLOCATE statement must be a variable name"_err_en_US ); |
33 | } else if (!IsAllocatableOrObjectPointer(symbol)) { // C936 |
34 | context_.Say(name.source, |
35 | "Name in DEALLOCATE statement must have the ALLOCATABLE or POINTER attribute"_err_en_US ); |
36 | } else if (auto whyNot{WhyNotDefinable(name.source, |
37 | context_.FindScope(name.source), |
38 | {DefinabilityFlag::PointerDefinition, |
39 | DefinabilityFlag::AcceptAllocatable, |
40 | DefinabilityFlag::PotentialDeallocation}, |
41 | *symbol)}) { |
42 | // Catch problems with non-definability of the |
43 | // pointer/allocatable |
44 | context_ |
45 | .Say(name.source, |
46 | "Name in DEALLOCATE statement is not definable"_err_en_US ) |
47 | .Attach(std::move( |
48 | whyNot->set_severity(parser::Severity::Because))); |
49 | } else if (auto whyNot{WhyNotDefinable(name.source, |
50 | context_.FindScope(name.source), |
51 | DefinabilityFlags{}, *symbol)}) { |
52 | // Catch problems with non-definability of the dynamic object |
53 | context_ |
54 | .Say(name.source, |
55 | "Object in DEALLOCATE statement is not deallocatable"_err_en_US ) |
56 | .Attach(std::move( |
57 | whyNot->set_severity(parser::Severity::Because))); |
58 | } else { |
59 | context_.CheckIndexVarRedefine(name); |
60 | } |
61 | }, |
62 | [&](const parser::StructureComponent &structureComponent) { |
63 | // Only perform structureComponent checks if it was successfully |
64 | // analyzed by expression analysis. |
65 | auto source{structureComponent.component.source}; |
66 | if (const auto *expr{GetExpr(context_, allocateObject)}) { |
67 | if (const Symbol * |
68 | symbol{structureComponent.component.symbol |
69 | ? &structureComponent.component.symbol |
70 | ->GetUltimate() |
71 | : nullptr}; |
72 | !IsAllocatableOrObjectPointer(symbol)) { // F'2023 C936 |
73 | context_.Say(source, |
74 | "Component in DEALLOCATE statement must have the ALLOCATABLE or POINTER attribute"_err_en_US ); |
75 | } else if (auto whyNot{WhyNotDefinable(source, |
76 | context_.FindScope(source), |
77 | {DefinabilityFlag::PointerDefinition, |
78 | DefinabilityFlag::AcceptAllocatable, |
79 | DefinabilityFlag::PotentialDeallocation}, |
80 | *expr)}) { |
81 | context_ |
82 | .Say(source, |
83 | "Name in DEALLOCATE statement is not definable"_err_en_US ) |
84 | .Attach(std::move( |
85 | whyNot->set_severity(parser::Severity::Because))); |
86 | } else if (auto whyNot{WhyNotDefinable(source, |
87 | context_.FindScope(source), DefinabilityFlags{}, |
88 | *expr)}) { |
89 | context_ |
90 | .Say(source, |
91 | "Object in DEALLOCATE statement is not deallocatable"_err_en_US ) |
92 | .Attach(std::move( |
93 | whyNot->set_severity(parser::Severity::Because))); |
94 | } else if (evaluate::ExtractCoarrayRef(*expr)) { // F'2023 C955 |
95 | context_.Say(source, |
96 | "Component in DEALLOCATE statement may not be coindexed"_err_en_US ); |
97 | } |
98 | } |
99 | }, |
100 | }, |
101 | allocateObject.u); |
102 | } |
103 | bool gotStat{false}, gotMsg{false}; |
104 | for (const parser::StatOrErrmsg &deallocOpt : |
105 | std::get<std::list<parser::StatOrErrmsg>>(deallocateStmt.t)) { |
106 | common::visit( |
107 | common::visitors{ |
108 | [&](const parser::StatVariable &) { |
109 | if (gotStat) { |
110 | context_.Say( |
111 | "STAT may not be duplicated in a DEALLOCATE statement"_err_en_US ); |
112 | } |
113 | gotStat = true; |
114 | }, |
115 | [&](const parser::MsgVariable &var) { |
116 | WarnOnDeferredLengthCharacterScalar(context_, |
117 | GetExpr(context_, var), var.v.thing.thing.GetSource(), |
118 | "ERRMSG=" ); |
119 | if (gotMsg) { |
120 | context_.Say( |
121 | "ERRMSG may not be duplicated in a DEALLOCATE statement"_err_en_US ); |
122 | } |
123 | gotMsg = true; |
124 | }, |
125 | }, |
126 | deallocOpt.u); |
127 | } |
128 | } |
129 | |
130 | } // namespace Fortran::semantics |
131 | |