1 //===-- lib/Semantics/semantics.cpp ---------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "flang/Semantics/semantics.h"
10 #include "assignment.h"
11 #include "canonicalize-acc.h"
12 #include "canonicalize-do.h"
13 #include "canonicalize-omp.h"
14 #include "check-acc-structure.h"
15 #include "check-allocate.h"
16 #include "check-arithmeticif.h"
17 #include "check-case.h"
18 #include "check-coarray.h"
19 #include "check-data.h"
20 #include "check-deallocate.h"
21 #include "check-declarations.h"
22 #include "check-do-forall.h"
23 #include "check-if-stmt.h"
25 #include "check-namelist.h"
26 #include "check-nullify.h"
27 #include "check-omp-structure.h"
28 #include "check-purity.h"
29 #include "check-return.h"
30 #include "check-select-rank.h"
31 #include "check-select-type.h"
32 #include "check-stop.h"
33 #include "compute-offsets.h"
35 #include "resolve-labels.h"
36 #include "resolve-names.h"
37 #include "rewrite-parse-tree.h"
38 #include "flang/Common/default-kinds.h"
39 #include "flang/Parser/parse-tree-visitor.h"
40 #include "flang/Parser/tools.h"
41 #include "flang/Semantics/expression.h"
42 #include "flang/Semantics/scope.h"
43 #include "flang/Semantics/symbol.h"
44 #include "llvm/Support/raw_ostream.h"
45 #include "llvm/TargetParser/Host.h"
46 #include "llvm/TargetParser/Triple.h"
48 namespace Fortran::semantics
{
50 using NameToSymbolMap
= std::multimap
<parser::CharBlock
, SymbolRef
>;
51 static void DoDumpSymbols(llvm::raw_ostream
&, const Scope
&, int indent
= 0);
52 static void PutIndent(llvm::raw_ostream
&, int indent
);
54 static void GetSymbolNames(const Scope
&scope
, NameToSymbolMap
&symbols
) {
55 // Finds all symbol names in the scope without collecting duplicates.
56 for (const auto &pair
: scope
) {
57 symbols
.emplace(pair
.second
->name(), *pair
.second
);
59 for (const auto &pair
: scope
.commonBlocks()) {
60 symbols
.emplace(pair
.second
->name(), *pair
.second
);
62 for (const auto &child
: scope
.children()) {
63 GetSymbolNames(child
, symbols
);
67 // A parse tree visitor that calls Enter/Leave functions from each checker
68 // class C supplied as template parameters. Enter is called before the node's
69 // children are visited, Leave is called after. No two checkers may have the
70 // same Enter or Leave function. Each checker must be constructible from
71 // SemanticsContext and have BaseChecker as a virtual base class.
72 template <typename
... C
> class SemanticsVisitor
: public virtual C
... {
76 using BaseChecker::Enter
;
77 using BaseChecker::Leave
;
78 SemanticsVisitor(SemanticsContext
&context
)
79 : C
{context
}..., context_
{context
} {}
81 template <typename N
> bool Pre(const N
&node
) {
82 if constexpr (common::HasMember
<const N
*, ConstructNode
>) {
83 context_
.PushConstruct(node
);
88 template <typename N
> void Post(const N
&node
) {
90 if constexpr (common::HasMember
<const N
*, ConstructNode
>) {
91 context_
.PopConstruct();
95 template <typename T
> bool Pre(const parser::Statement
<T
> &node
) {
96 context_
.set_location(node
.source
);
100 template <typename T
> bool Pre(const parser::UnlabeledStatement
<T
> &node
) {
101 context_
.set_location(node
.source
);
105 template <typename T
> void Post(const parser::Statement
<T
> &node
) {
107 context_
.set_location(std::nullopt
);
109 template <typename T
> void Post(const parser::UnlabeledStatement
<T
> &node
) {
111 context_
.set_location(std::nullopt
);
114 bool Walk(const parser::Program
&program
) {
115 parser::Walk(program
, *this);
116 return !context_
.AnyFatalError();
120 SemanticsContext
&context_
;
123 class MiscChecker
: public virtual BaseChecker
{
125 explicit MiscChecker(SemanticsContext
&context
) : context_
{context
} {}
126 void Leave(const parser::EntryStmt
&) {
127 if (!context_
.constructStack().empty()) { // C1571
128 context_
.Say("ENTRY may not appear in an executable construct"_err_en_US
);
131 void Leave(const parser::AssignStmt
&stmt
) {
132 CheckAssignGotoName(std::get
<parser::Name
>(stmt
.t
));
134 void Leave(const parser::AssignedGotoStmt
&stmt
) {
135 CheckAssignGotoName(std::get
<parser::Name
>(stmt
.t
));
139 void CheckAssignGotoName(const parser::Name
&name
) {
140 if (context_
.HasError(name
.symbol
)) {
143 const Symbol
&symbol
{DEREF(name
.symbol
)};
144 auto type
{evaluate::DynamicType::From(symbol
)};
145 if (!IsVariableName(symbol
) || symbol
.Rank() != 0 || !type
||
146 type
->category() != TypeCategory::Integer
||
148 context_
.defaultKinds().GetDefaultKind(TypeCategory::Integer
)) {
151 "'%s' must be a default integer scalar variable"_err_en_US
,
153 .Attach(symbol
.name(), "Declaration of '%s'"_en_US
, symbol
.name());
157 SemanticsContext
&context_
;
160 using StatementSemanticsPass1
= ExprChecker
;
161 using StatementSemanticsPass2
= SemanticsVisitor
<AccStructureChecker
,
162 AllocateChecker
, ArithmeticIfStmtChecker
, AssignmentChecker
, CaseChecker
,
163 CoarrayChecker
, DataChecker
, DeallocateChecker
, DoForallChecker
,
164 IfStmtChecker
, IoChecker
, MiscChecker
, NamelistChecker
, NullifyChecker
,
165 OmpStructureChecker
, PurityChecker
, ReturnStmtChecker
,
166 SelectRankConstructChecker
, SelectTypeChecker
, StopChecker
>;
168 static bool PerformStatementSemantics(
169 SemanticsContext
&context
, parser::Program
&program
) {
170 ResolveNames(context
, program
, context
.globalScope());
171 RewriteParseTree(context
, program
);
172 ComputeOffsets(context
, context
.globalScope());
173 CheckDeclarations(context
);
174 StatementSemanticsPass1
{context
}.Walk(program
);
175 StatementSemanticsPass2 pass2
{context
};
177 if (!context
.AnyFatalError()) {
178 pass2
.CompileDataInitializationsIntoInitializers();
180 return !context
.AnyFatalError();
183 /// This class keeps track of the common block appearances with the biggest size
184 /// and with an initial value (if any) in a program. This allows reporting
185 /// conflicting initialization and warning about appearances of a same
186 /// named common block with different sizes. The biggest common block size and
187 /// initialization (if any) can later be provided so that lowering can generate
188 /// the correct symbol size and initial values, even when named common blocks
189 /// appears with different sizes and are initialized outside of block data.
190 class CommonBlockMap
{
192 struct CommonBlockInfo
{
193 // Common block symbol for the appearance with the biggest size.
194 SymbolRef biggestSize
;
195 // Common block symbol for the appearance with the initialized members (if
197 std::optional
<SymbolRef
> initialization
;
201 void MapCommonBlockAndCheckConflicts(
202 SemanticsContext
&context
, const Symbol
&common
) {
203 const Symbol
*isInitialized
{CommonBlockIsInitialized(common
)};
204 auto [it
, firstAppearance
] = commonBlocks_
.insert({common
.name(),
205 isInitialized
? CommonBlockInfo
{common
, common
}
206 : CommonBlockInfo
{common
, std::nullopt
}});
207 if (!firstAppearance
) {
208 CommonBlockInfo
&info
{it
->second
};
210 if (info
.initialization
.has_value() &&
211 &**info
.initialization
!= &common
) {
212 // Use the location of the initialization in the error message because
213 // common block symbols may have no location if they are blank
215 const Symbol
&previousInit
{
216 DEREF(CommonBlockIsInitialized(**info
.initialization
))};
218 .Say(isInitialized
->name(),
219 "Multiple initialization of COMMON block /%s/"_err_en_US
,
221 .Attach(previousInit
.name(),
222 "Previous initialization of COMMON block /%s/"_en_US
,
225 info
.initialization
= common
;
228 if (common
.size() != info
.biggestSize
->size() && !common
.name().empty()) {
231 "A named COMMON block should have the same size everywhere it appears (%zd bytes here)"_port_en_US
,
233 .Attach(info
.biggestSize
->name(),
234 "Previously defined with a size of %zd bytes"_en_US
,
235 info
.biggestSize
->size());
237 if (common
.size() > info
.biggestSize
->size()) {
238 info
.biggestSize
= common
;
243 CommonBlockList
GetCommonBlocks() const {
244 CommonBlockList result
;
245 for (const auto &[_
, blockInfo
] : commonBlocks_
) {
247 std::make_pair(blockInfo
.initialization
? *blockInfo
.initialization
248 : blockInfo
.biggestSize
,
249 blockInfo
.biggestSize
->size()));
255 /// Return the symbol of an initialized member if a COMMON block
256 /// is initalized. Otherwise, return nullptr.
257 static Symbol
*CommonBlockIsInitialized(const Symbol
&common
) {
258 const auto &commonDetails
=
259 common
.get
<Fortran::semantics::CommonBlockDetails
>();
261 for (const auto &member
: commonDetails
.objects()) {
262 if (IsInitialized(*member
)) {
267 // Common block may be initialized via initialized variables that are in an
268 // equivalence with the common block members.
269 for (const Fortran::semantics::EquivalenceSet
&set
:
270 common
.owner().equivalenceSets()) {
271 for (const Fortran::semantics::EquivalenceObject
&obj
: set
) {
272 if (!obj
.symbol
.test(
273 Fortran::semantics::Symbol::Flag::CompilerCreated
)) {
274 if (FindCommonBlockContaining(obj
.symbol
) == &common
&&
275 IsInitialized(obj
.symbol
)) {
283 std::map
<SourceName
, CommonBlockInfo
> commonBlocks_
;
286 SemanticsContext::SemanticsContext(
287 const common::IntrinsicTypeDefaultKinds
&defaultKinds
,
288 const common::LanguageFeatureControl
&languageFeatures
,
289 parser::AllCookedSources
&allCookedSources
)
290 : defaultKinds_
{defaultKinds
}, languageFeatures_
{languageFeatures
},
291 allCookedSources_
{allCookedSources
},
292 intrinsics_
{evaluate::IntrinsicProcTable::Configure(defaultKinds_
)},
293 globalScope_
{*this}, intrinsicModulesScope_
{globalScope_
.MakeScope(
294 Scope::Kind::IntrinsicModules
, nullptr)},
295 foldingContext_
{parser::ContextualMessages
{&messages_
}, defaultKinds_
,
296 intrinsics_
, targetCharacteristics_
} {}
298 SemanticsContext::~SemanticsContext() {}
300 int SemanticsContext::GetDefaultKind(TypeCategory category
) const {
301 return defaultKinds_
.GetDefaultKind(category
);
304 const DeclTypeSpec
&SemanticsContext::MakeNumericType(
305 TypeCategory category
, int kind
) {
307 kind
= GetDefaultKind(category
);
309 return globalScope_
.MakeNumericType(category
, KindExpr
{kind
});
311 const DeclTypeSpec
&SemanticsContext::MakeLogicalType(int kind
) {
313 kind
= GetDefaultKind(TypeCategory::Logical
);
315 return globalScope_
.MakeLogicalType(KindExpr
{kind
});
318 bool SemanticsContext::AnyFatalError() const {
319 return !messages_
.empty() &&
320 (warningsAreErrors_
|| messages_
.AnyFatalError());
322 bool SemanticsContext::HasError(const Symbol
&symbol
) {
323 return errorSymbols_
.count(symbol
) > 0;
325 bool SemanticsContext::HasError(const Symbol
*symbol
) {
326 return !symbol
|| HasError(*symbol
);
328 bool SemanticsContext::HasError(const parser::Name
&name
) {
329 return HasError(name
.symbol
);
331 void SemanticsContext::SetError(const Symbol
&symbol
, bool value
) {
334 errorSymbols_
.emplace(symbol
);
337 void SemanticsContext::CheckError(const Symbol
&symbol
) {
338 if (!AnyFatalError()) {
340 llvm::raw_string_ostream ss
{buf
};
343 "No error was reported but setting error on: %s", ss
.str().c_str());
347 const Scope
&SemanticsContext::FindScope(parser::CharBlock source
) const {
348 return const_cast<SemanticsContext
*>(this)->FindScope(source
);
351 Scope
&SemanticsContext::FindScope(parser::CharBlock source
) {
352 if (auto *scope
{globalScope_
.FindScope(source
)}) {
356 "SemanticsContext::FindScope(): invalid source location for '%s'",
357 source
.ToString().c_str());
361 bool SemanticsContext::IsInModuleFile(parser::CharBlock source
) const {
362 for (const Scope
*scope
{&FindScope(source
)}; !scope
->IsGlobal();
363 scope
= &scope
->parent()) {
364 if (scope
->IsModuleFile()) {
371 void SemanticsContext::PopConstruct() {
372 CHECK(!constructStack_
.empty());
373 constructStack_
.pop_back();
376 void SemanticsContext::CheckIndexVarRedefine(const parser::CharBlock
&location
,
377 const Symbol
&variable
, parser::MessageFixedText
&&message
) {
378 const Symbol
&symbol
{ResolveAssociations(variable
)};
379 auto it
{activeIndexVars_
.find(symbol
)};
380 if (it
!= activeIndexVars_
.end()) {
381 std::string kind
{EnumToString(it
->second
.kind
)};
382 Say(location
, std::move(message
), kind
, symbol
.name())
383 .Attach(it
->second
.location
, "Enclosing %s construct"_en_US
, kind
);
387 void SemanticsContext::WarnIndexVarRedefine(
388 const parser::CharBlock
&location
, const Symbol
&variable
) {
389 CheckIndexVarRedefine(location
, variable
,
390 "Possible redefinition of %s variable '%s'"_warn_en_US
);
393 void SemanticsContext::CheckIndexVarRedefine(
394 const parser::CharBlock
&location
, const Symbol
&variable
) {
395 CheckIndexVarRedefine(
396 location
, variable
, "Cannot redefine %s variable '%s'"_err_en_US
);
399 void SemanticsContext::CheckIndexVarRedefine(const parser::Variable
&variable
) {
400 if (const Symbol
* entity
{GetLastName(variable
).symbol
}) {
401 CheckIndexVarRedefine(variable
.GetSource(), *entity
);
405 void SemanticsContext::CheckIndexVarRedefine(const parser::Name
&name
) {
406 if (const Symbol
* entity
{name
.symbol
}) {
407 CheckIndexVarRedefine(name
.source
, *entity
);
411 void SemanticsContext::ActivateIndexVar(
412 const parser::Name
&name
, IndexVarKind kind
) {
413 CheckIndexVarRedefine(name
);
414 if (const Symbol
* indexVar
{name
.symbol
}) {
415 activeIndexVars_
.emplace(
416 ResolveAssociations(*indexVar
), IndexVarInfo
{name
.source
, kind
});
420 void SemanticsContext::DeactivateIndexVar(const parser::Name
&name
) {
421 if (Symbol
* indexVar
{name
.symbol
}) {
422 auto it
{activeIndexVars_
.find(ResolveAssociations(*indexVar
))};
423 if (it
!= activeIndexVars_
.end() && it
->second
.location
== name
.source
) {
424 activeIndexVars_
.erase(it
);
429 SymbolVector
SemanticsContext::GetIndexVars(IndexVarKind kind
) {
431 for (const auto &[symbol
, info
] : activeIndexVars_
) {
432 if (info
.kind
== kind
) {
433 result
.push_back(symbol
);
439 SourceName
SemanticsContext::SaveTempName(std::string
&&name
) {
440 return {*tempNames_
.emplace(std::move(name
)).first
};
443 SourceName
SemanticsContext::GetTempName(const Scope
&scope
) {
444 for (const auto &str
: tempNames_
) {
445 if (IsTempName(str
)) {
446 SourceName name
{str
};
447 if (scope
.find(name
) == scope
.end()) {
452 return SaveTempName(".F18."s
+ std::to_string(tempNames_
.size()));
455 bool SemanticsContext::IsTempName(const std::string
&name
) {
456 return name
.size() > 5 && name
.substr(0, 5) == ".F18.";
459 Scope
*SemanticsContext::GetBuiltinModule(const char *name
) {
460 return ModFileReader
{*this}.Read(SourceName
{name
, std::strlen(name
)},
461 true /*intrinsic*/, nullptr, true /*silence errors*/);
464 void SemanticsContext::UseFortranBuiltinsModule() {
465 if (builtinsScope_
== nullptr) {
466 builtinsScope_
= GetBuiltinModule("__fortran_builtins");
467 if (builtinsScope_
) {
468 intrinsics_
.SupplyBuiltins(*builtinsScope_
);
473 void SemanticsContext::UsePPCFortranBuiltinsModule() {
474 if (ppcBuiltinsScope_
== nullptr) {
475 ppcBuiltinsScope_
= GetBuiltinModule("__fortran_ppc_intrinsics");
479 parser::Program
&SemanticsContext::SaveParseTree(parser::Program
&&tree
) {
480 return modFileParseTrees_
.emplace_back(std::move(tree
));
483 bool Semantics::Perform() {
484 // Implicitly USE the __Fortran_builtins module so that special types
485 // (e.g., __builtin_team_type) are available to semantics, esp. for
486 // intrinsic checking.
487 if (!program_
.v
.empty()) {
488 const auto *frontModule
{std::get_if
<common::Indirection
<parser::Module
>>(
489 &program_
.v
.front().u
)};
491 (std::get
<parser::Statement
<parser::ModuleStmt
>>(frontModule
->value().t
)
492 .statement
.v
.source
== "__fortran_builtins" ||
493 std::get
<parser::Statement
<parser::ModuleStmt
>>(
494 frontModule
->value().t
)
495 .statement
.v
.source
== "__fortran_ppc_intrinsics")) {
496 // Don't try to read the builtins module when we're actually building it.
498 context_
.UseFortranBuiltinsModule();
499 llvm::Triple targetTriple
{llvm::Triple(
500 llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple()))};
501 // Only use __Fortran_PPC_intrinsics module when targetting PowerPC arch
502 if (targetTriple
.isPPC()) {
503 context_
.UsePPCFortranBuiltinsModule();
507 return ValidateLabels(context_
, program_
) &&
508 parser::CanonicalizeDo(program_
) && // force line break
509 CanonicalizeAcc(context_
.messages(), program_
) &&
510 CanonicalizeOmp(context_
.messages(), program_
) &&
511 PerformStatementSemantics(context_
, program_
) &&
512 ModFileWriter
{context_
}.WriteAll();
515 void Semantics::EmitMessages(llvm::raw_ostream
&os
) const {
516 context_
.messages().Emit(os
, context_
.allCookedSources());
519 void Semantics::DumpSymbols(llvm::raw_ostream
&os
) {
520 DoDumpSymbols(os
, context_
.globalScope());
523 void Semantics::DumpSymbolsSources(llvm::raw_ostream
&os
) const {
524 NameToSymbolMap symbols
;
525 GetSymbolNames(context_
.globalScope(), symbols
);
526 const parser::AllCookedSources
&allCooked
{context_
.allCookedSources()};
527 for (const auto &pair
: symbols
) {
528 const Symbol
&symbol
{pair
.second
};
529 if (auto sourceInfo
{allCooked
.GetSourcePositionRange(symbol
.name())}) {
530 os
<< symbol
.name().ToString() << ": " << sourceInfo
->first
.file
.path()
531 << ", " << sourceInfo
->first
.line
<< ", " << sourceInfo
->first
.column
532 << "-" << sourceInfo
->second
.column
<< "\n";
533 } else if (symbol
.has
<semantics::UseDetails
>()) {
534 os
<< symbol
.name().ToString() << ": "
535 << symbol
.GetUltimate().owner().symbol()->name().ToString() << "\n";
540 void DoDumpSymbols(llvm::raw_ostream
&os
, const Scope
&scope
, int indent
) {
541 PutIndent(os
, indent
);
542 os
<< Scope::EnumToString(scope
.kind()) << " scope:";
543 if (const auto *symbol
{scope
.symbol()}) {
544 os
<< ' ' << symbol
->name();
546 if (scope
.alignment().has_value()) {
547 os
<< " size=" << scope
.size() << " alignment=" << *scope
.alignment();
549 if (scope
.derivedTypeSpec()) {
550 os
<< " instantiation of " << *scope
.derivedTypeSpec();
554 for (const auto &pair
: scope
) {
555 const auto &symbol
{*pair
.second
};
556 PutIndent(os
, indent
);
557 os
<< symbol
<< '\n';
558 if (const auto *details
{symbol
.detailsIf
<GenericDetails
>()}) {
559 if (const auto &type
{details
->derivedType()}) {
560 PutIndent(os
, indent
);
565 if (!scope
.equivalenceSets().empty()) {
566 PutIndent(os
, indent
);
567 os
<< "Equivalence Sets:";
568 for (const auto &set
: scope
.equivalenceSets()) {
571 for (const auto &object
: set
) {
572 os
<< sep
<< object
.AsFortran();
579 if (!scope
.crayPointers().empty()) {
580 PutIndent(os
, indent
);
581 os
<< "Cray Pointers:";
582 for (const auto &[pointee
, pointer
] : scope
.crayPointers()) {
583 os
<< " (" << pointer
->name() << ',' << pointee
<< ')';
586 for (const auto &pair
: scope
.commonBlocks()) {
587 const auto &symbol
{*pair
.second
};
588 PutIndent(os
, indent
);
589 os
<< symbol
<< '\n';
591 for (const auto &child
: scope
.children()) {
592 DoDumpSymbols(os
, child
, indent
);
597 static void PutIndent(llvm::raw_ostream
&os
, int indent
) {
598 for (int i
= 0; i
< indent
; ++i
) {
603 void SemanticsContext::MapCommonBlockAndCheckConflicts(const Symbol
&common
) {
604 if (!commonBlockMap_
) {
605 commonBlockMap_
= std::make_unique
<CommonBlockMap
>();
607 commonBlockMap_
->MapCommonBlockAndCheckConflicts(*this, common
);
610 CommonBlockList
SemanticsContext::GetCommonBlocks() const {
611 if (commonBlockMap_
) {
612 return commonBlockMap_
->GetCommonBlocks();
617 } // namespace Fortran::semantics