summaryrefslogtreecommitdiff
path: root/flang/lib/Semantics
diff options
context:
space:
mode:
authorPeter Collingbourne <peter@pcc.me.uk>2025-07-18 13:26:00 -0700
committerPeter Collingbourne <peter@pcc.me.uk>2025-07-18 13:26:00 -0700
commit9bf3524731070cadc6175707314f3b6ca37190d5 (patch)
tree86dcab7604336b01ae938fe81062c29ff69efba8 /flang/lib/Semantics
parent3a84c15cc13b6daf8e812592898ab6c7f19091a9 (diff)
parent4f43f0606c3d7e1ce6d069583b5e59f036e112ce (diff)
Created using spr 1.3.6-beta.1
Diffstat (limited to 'flang/lib/Semantics')
-rw-r--r--flang/lib/Semantics/check-declarations.cpp48
-rw-r--r--flang/lib/Semantics/check-do-forall.cpp4
-rw-r--r--flang/lib/Semantics/check-omp-structure.cpp3
-rw-r--r--flang/lib/Semantics/expression.cpp68
-rw-r--r--flang/lib/Semantics/resolve-labels.cpp25
-rw-r--r--flang/lib/Semantics/resolve-names.cpp8
-rw-r--r--flang/lib/Semantics/runtime-type-info.cpp28
-rw-r--r--flang/lib/Semantics/semantics.cpp5
-rw-r--r--flang/lib/Semantics/tools.cpp8
9 files changed, 129 insertions, 68 deletions
diff --git a/flang/lib/Semantics/check-declarations.cpp b/flang/lib/Semantics/check-declarations.cpp
index f9d64485f140..a2f2906af10b 100644
--- a/flang/lib/Semantics/check-declarations.cpp
+++ b/flang/lib/Semantics/check-declarations.cpp
@@ -151,8 +151,8 @@ private:
void CheckProcedureAssemblyName(const Symbol &symbol);
void CheckExplicitSave(const Symbol &);
parser::Messages WhyNotInteroperableDerivedType(const Symbol &);
- parser::Messages WhyNotInteroperableObject(
- const Symbol &, bool allowNonInteroperableType = false);
+ parser::Messages WhyNotInteroperableObject(const Symbol &,
+ bool allowNonInteroperableType = false, bool forCommonBlock = false);
parser::Messages WhyNotInteroperableFunctionResult(const Symbol &);
parser::Messages WhyNotInteroperableProcedure(const Symbol &, bool isError);
void CheckBindC(const Symbol &);
@@ -519,11 +519,35 @@ void CheckHelper::Check(const Symbol &symbol) {
}
void CheckHelper::CheckCommonBlock(const Symbol &symbol) {
+ auto restorer{messages_.SetLocation(symbol.name())};
CheckGlobalName(symbol);
if (symbol.attrs().test(Attr::BIND_C)) {
CheckBindC(symbol);
+ for (auto ref : symbol.get<CommonBlockDetails>().objects()) {
+ if (ref->has<ObjectEntityDetails>()) {
+ if (auto msgs{WhyNotInteroperableObject(*ref,
+ /*allowInteroperableType=*/false, /*forCommonBlock=*/true)};
+ !msgs.empty()) {
+ parser::Message &reason{msgs.messages().front()};
+ parser::Message *msg{nullptr};
+ if (reason.IsFatal()) {
+ msg = messages_.Say(symbol.name(),
+ "'%s' may not be a member of BIND(C) COMMON block /%s/"_err_en_US,
+ ref->name(), symbol.name());
+ } else {
+ msg = messages_.Say(symbol.name(),
+ "'%s' should not be a member of BIND(C) COMMON block /%s/"_warn_en_US,
+ ref->name(), symbol.name());
+ }
+ if (msg) {
+ msg->Attach(
+ std::move(reason.set_severity(parser::Severity::Because)));
+ }
+ }
+ }
+ }
}
- for (MutableSymbolRef ref : symbol.get<CommonBlockDetails>().objects()) {
+ for (auto ref : symbol.get<CommonBlockDetails>().objects()) {
if (ref->test(Symbol::Flag::CrayPointee)) {
messages_.Say(ref->name(),
"Cray pointee '%s' may not be a member of a COMMON block"_err_en_US,
@@ -3154,14 +3178,16 @@ parser::Messages CheckHelper::WhyNotInteroperableDerivedType(
}
parser::Messages CheckHelper::WhyNotInteroperableObject(
- const Symbol &symbol, bool allowNonInteroperableType) {
+ const Symbol &symbol, bool allowNonInteroperableType, bool forCommonBlock) {
parser::Messages msgs;
- if (examinedByWhyNotInteroperable_.find(symbol) !=
- examinedByWhyNotInteroperable_.end()) {
- return msgs;
+ if (!forCommonBlock) {
+ if (examinedByWhyNotInteroperable_.find(symbol) !=
+ examinedByWhyNotInteroperable_.end()) {
+ return msgs;
+ }
+ examinedByWhyNotInteroperable_.insert(symbol);
}
bool isExplicitBindC{symbol.attrs().test(Attr::BIND_C)};
- examinedByWhyNotInteroperable_.insert(symbol);
CHECK(symbol.has<ObjectEntityDetails>());
if (isExplicitBindC && !symbol.owner().IsModule()) {
msgs.Say(symbol.name(),
@@ -3258,7 +3284,7 @@ parser::Messages CheckHelper::WhyNotInteroperableObject(
msgs.Say(symbol.name(),
"An interoperable pointer must not be CONTIGUOUS"_err_en_US);
}
- if (msgs.AnyFatalError()) {
+ if (!forCommonBlock && msgs.AnyFatalError()) {
examinedByWhyNotInteroperable_.erase(symbol);
}
return msgs;
@@ -3338,8 +3364,8 @@ parser::Messages CheckHelper::WhyNotInteroperableProcedure(
// on the C side by either a cdesc_t * or a void *. F'2023 18.3.7 (5)
bool allowNonInteroperableType{!dummy->attrs().test(Attr::VALUE) &&
(IsDescriptor(*dummy) || IsAssumedType(*dummy))};
- dummyMsgs =
- WhyNotInteroperableObject(*dummy, allowNonInteroperableType);
+ dummyMsgs = WhyNotInteroperableObject(
+ *dummy, allowNonInteroperableType, /*forCommonBlock=*/false);
} else {
CheckBindC(*dummy);
}
diff --git a/flang/lib/Semantics/check-do-forall.cpp b/flang/lib/Semantics/check-do-forall.cpp
index cc1d4bf58745..e258df86a4b1 100644
--- a/flang/lib/Semantics/check-do-forall.cpp
+++ b/flang/lib/Semantics/check-do-forall.cpp
@@ -1180,7 +1180,9 @@ void DoForallChecker::Leave(const parser::IoControlSpec &ioControlSpec) {
void DoForallChecker::Leave(const parser::OutputImpliedDo &outputImpliedDo) {
const auto &control{std::get<parser::IoImpliedDoControl>(outputImpliedDo.t)};
const parser::Name &name{control.name.thing.thing};
- context_.CheckIndexVarRedefine(name.source, *name.symbol);
+ if (name.symbol) {
+ context_.CheckIndexVarRedefine(name.source, *name.symbol);
+ }
}
void DoForallChecker::Leave(const parser::StatVariable &statVariable) {
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 2425265e196c..e4a94efcc6b5 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -1156,8 +1156,7 @@ void OmpStructureChecker::CheckThreadprivateOrDeclareTargetVar(
(sym->has<MainProgramDetails>() ||
sym->has<ModuleDetails>())) {
context_.Say(name->source,
- "The module name or main program name cannot be in a "
- "%s "
+ "The module name cannot be in a %s "
"directive"_err_en_US,
ContextDirectiveAsFortran());
} else if (!IsSaved(*name->symbol) &&
diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp
index f4af738284ed..14473724f0f4 100644
--- a/flang/lib/Semantics/expression.cpp
+++ b/flang/lib/Semantics/expression.cpp
@@ -178,7 +178,7 @@ public:
}
// Find and return a user-defined assignment
std::optional<ProcedureRef> TryDefinedAssignment();
- std::optional<ProcedureRef> GetDefinedAssignmentProc();
+ std::optional<ProcedureRef> GetDefinedAssignmentProc(bool &isAmbiguous);
std::optional<DynamicType> GetType(std::size_t) const;
void Dump(llvm::raw_ostream &);
@@ -191,7 +191,7 @@ private:
MaybeExpr AnalyzeExprOrWholeAssumedSizeArray(const parser::Expr &);
bool AreConformable() const;
const Symbol *FindBoundOp(parser::CharBlock, int passIndex,
- const Symbol *&generic, bool isSubroutine);
+ const Symbol *&generic, bool isSubroutine, bool *isAmbiguous = nullptr);
void AddAssignmentConversion(
const DynamicType &lhsType, const DynamicType &rhsType);
bool OkLogicalIntegerAssignment(TypeCategory lhs, TypeCategory rhs);
@@ -199,7 +199,8 @@ private:
bool IsBOZLiteral(std::size_t i) const {
return evaluate::IsBOZLiteral(GetExpr(i));
}
- void SayNoMatch(const std::string &, bool isAssignment = false);
+ void SayNoMatch(
+ const std::string &, bool isAssignment = false, bool isAmbiguous = false);
std::string TypeAsFortran(std::size_t);
bool AnyUntypedOrMissingOperand();
@@ -1269,7 +1270,7 @@ MaybeExpr ExpressionAnalyzer::Analyze(
MaybeExpr ExpressionAnalyzer::Analyze(const parser::SubstringInquiry &x) {
if (MaybeExpr substring{Analyze(x.v)}) {
CHECK(x.source.size() >= 8);
- int nameLen{x.source.end()[-1] == 'n' ? 3 /*LEN*/ : 4 /*KIND*/};
+ int nameLen{x.source.back() == 'n' ? 3 /*LEN*/ : 4 /*KIND*/};
parser::CharBlock name{
x.source.end() - nameLen, static_cast<std::size_t>(nameLen)};
CHECK(name == "len" || name == "kind");
@@ -4781,7 +4782,9 @@ std::optional<ProcedureRef> ArgumentAnalyzer::TryDefinedAssignment() {
return std::nullopt; // user-defined assignment not allowed for these args
}
auto restorer{context_.GetContextualMessages().SetLocation(source_)};
- if (std::optional<ProcedureRef> procRef{GetDefinedAssignmentProc()}) {
+ bool isAmbiguous{false};
+ if (std::optional<ProcedureRef> procRef{
+ GetDefinedAssignmentProc(isAmbiguous)}) {
if (context_.inWhereBody() && !procRef->proc().IsElemental()) { // C1032
context_.Say(
"Defined assignment in WHERE must be elemental, but '%s' is not"_err_en_US,
@@ -4791,9 +4794,11 @@ std::optional<ProcedureRef> ArgumentAnalyzer::TryDefinedAssignment() {
return std::move(*procRef);
}
if (isDefined == Tristate::Yes) {
- if (!lhsType || !rhsType || (lhsRank != rhsRank && rhsRank != 0) ||
+ if (isAmbiguous || !lhsType || !rhsType ||
+ (lhsRank != rhsRank && rhsRank != 0) ||
!OkLogicalIntegerAssignment(lhsType->category(), rhsType->category())) {
- SayNoMatch("ASSIGNMENT(=)", true);
+ SayNoMatch(
+ "ASSIGNMENT(=)", /*isAssignment=*/true, /*isAmbiguous=*/isAmbiguous);
}
} else if (!fatalErrors_) {
CheckAssignmentConformance();
@@ -4822,13 +4827,15 @@ bool ArgumentAnalyzer::OkLogicalIntegerAssignment(
return true;
}
-std::optional<ProcedureRef> ArgumentAnalyzer::GetDefinedAssignmentProc() {
+std::optional<ProcedureRef> ArgumentAnalyzer::GetDefinedAssignmentProc(
+ bool &isAmbiguous) {
const Symbol *proc{nullptr};
bool isProcElemental{false};
std::optional<int> passedObjectIndex;
std::string oprNameString{"assignment(=)"};
parser::CharBlock oprName{oprNameString};
const auto &scope{context_.context().FindScope(source_)};
+ isAmbiguous = false;
{
auto restorer{context_.GetContextualMessages().DiscardMessages()};
if (const Symbol *symbol{scope.FindSymbol(oprName)}) {
@@ -4842,8 +4849,8 @@ std::optional<ProcedureRef> ArgumentAnalyzer::GetDefinedAssignmentProc() {
for (std::size_t i{0}; (!proc || isProcElemental) && i < actuals_.size();
++i) {
const Symbol *generic{nullptr};
- if (const Symbol *
- binding{FindBoundOp(oprName, i, generic, /*isSubroutine=*/true)}) {
+ if (const Symbol *binding{FindBoundOp(oprName, i, generic,
+ /*isSubroutine=*/true, /*isAmbiguous=*/&isAmbiguous)}) {
// ignore inaccessible type-bound ASSIGNMENT(=) generic
if (!CheckAccessibleSymbol(scope, DEREF(generic))) {
const Symbol *resolution{GetBindingResolution(GetType(i), *binding)};
@@ -4967,7 +4974,8 @@ bool ArgumentAnalyzer::AreConformable() const {
// Look for a type-bound operator in the type of arg number passIndex.
const Symbol *ArgumentAnalyzer::FindBoundOp(parser::CharBlock oprName,
- int passIndex, const Symbol *&generic, bool isSubroutine) {
+ int passIndex, const Symbol *&generic, bool isSubroutine,
+ bool *isAmbiguous) {
const auto *type{GetDerivedTypeSpec(GetType(passIndex))};
const semantics::Scope *scope{type ? type->scope() : nullptr};
if (scope) {
@@ -4989,6 +4997,9 @@ const Symbol *ArgumentAnalyzer::FindBoundOp(parser::CharBlock oprName,
// Use the most recent override of the binding, if any
return scope->FindComponent(binding->name());
} else {
+ if (isAmbiguous) {
+ *isAmbiguous = pair.second;
+ }
context_.EmitGenericResolutionError(*generic, pair.second, isSubroutine);
}
}
@@ -5072,40 +5083,37 @@ void ArgumentAnalyzer::ConvertBOZAssignmentRHS(const DynamicType &lhsType) {
}
// Report error resolving opr when there is a user-defined one available
-void ArgumentAnalyzer::SayNoMatch(const std::string &opr, bool isAssignment) {
+void ArgumentAnalyzer::SayNoMatch(
+ const std::string &opr, bool isAssignment, bool isAmbiguous) {
std::string type0{TypeAsFortran(0)};
auto rank0{actuals_[0]->Rank()};
+ std::string prefix{"No intrinsic or user-defined "s + opr + " matches"};
+ if (isAmbiguous) {
+ prefix = "Multiple specific procedures for the generic "s + opr + " match";
+ }
if (actuals_.size() == 1) {
if (rank0 > 0) {
- context_.Say("No intrinsic or user-defined %s matches "
- "rank %d array of %s"_err_en_US,
- opr, rank0, type0);
+ context_.Say("%s rank %d array of %s"_err_en_US, prefix, rank0, type0);
} else {
- context_.Say("No intrinsic or user-defined %s matches "
- "operand type %s"_err_en_US,
- opr, type0);
+ context_.Say("%s operand type %s"_err_en_US, prefix, type0);
}
} else {
std::string type1{TypeAsFortran(1)};
auto rank1{actuals_[1]->Rank()};
if (rank0 > 0 && rank1 > 0 && rank0 != rank1) {
- context_.Say("No intrinsic or user-defined %s matches "
- "rank %d array of %s and rank %d array of %s"_err_en_US,
- opr, rank0, type0, rank1, type1);
+ context_.Say("%s rank %d array of %s and rank %d array of %s"_err_en_US,
+ prefix, rank0, type0, rank1, type1);
} else if (isAssignment && rank0 != rank1) {
if (rank0 == 0) {
- context_.Say("No intrinsic or user-defined %s matches "
- "scalar %s and rank %d array of %s"_err_en_US,
- opr, type0, rank1, type1);
+ context_.Say("%s scalar %s and rank %d array of %s"_err_en_US, prefix,
+ type0, rank1, type1);
} else {
- context_.Say("No intrinsic or user-defined %s matches "
- "rank %d array of %s and scalar %s"_err_en_US,
- opr, rank0, type0, type1);
+ context_.Say("%s rank %d array of %s and scalar %s"_err_en_US, prefix,
+ rank0, type0, type1);
}
} else {
- context_.Say("No intrinsic or user-defined %s matches "
- "operand types %s and %s"_err_en_US,
- opr, type0, type1);
+ context_.Say(
+ "%s operand types %s and %s"_err_en_US, prefix, type0, type1);
}
}
}
diff --git a/flang/lib/Semantics/resolve-labels.cpp b/flang/lib/Semantics/resolve-labels.cpp
index b0cbc4b56e88..27e259fab387 100644
--- a/flang/lib/Semantics/resolve-labels.cpp
+++ b/flang/lib/Semantics/resolve-labels.cpp
@@ -489,15 +489,30 @@ public:
// C1401
void Post(const parser::MainProgram &mainProgram) {
+ // Uppercase the name of the main program, so that its symbol name
+ // would be unique from similarly named non-main-program symbols.
+ auto upperCaseCharBlock = [](const parser::CharBlock &cb) {
+ char *ch{const_cast<char *>(cb.begin())};
+ char *endCh{ch + cb.size()};
+ while (ch != endCh) {
+ *ch++ = parser::ToUpperCaseLetter(*ch);
+ }
+ };
+ const parser::CharBlock *progName{nullptr};
+ if (const auto &program{
+ std::get<std::optional<parser::Statement<parser::ProgramStmt>>>(
+ mainProgram.t)}) {
+ progName = &program->statement.v.source;
+ upperCaseCharBlock(*progName);
+ }
if (const parser::CharBlock *
endName{GetStmtName(std::get<parser::Statement<parser::EndProgramStmt>>(
mainProgram.t))}) {
- if (const auto &program{
- std::get<std::optional<parser::Statement<parser::ProgramStmt>>>(
- mainProgram.t)}) {
- if (*endName != program->statement.v.source) {
+ upperCaseCharBlock(*endName);
+ if (progName) {
+ if (*endName != *progName) {
context_.Say(*endName, "END PROGRAM name mismatch"_err_en_US)
- .Attach(program->statement.v.source, "should be"_en_US);
+ .Attach(*progName, "should be"_en_US);
}
} else {
context_.Say(*endName,
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index d0336c9cb661..b3268605e7c0 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -2139,7 +2139,7 @@ bool ImplicitRules::isImplicitNoneExternal() const {
const DeclTypeSpec *ImplicitRules::GetType(
SourceName name, bool respectImplicitNoneType) const {
- char ch{name.begin()[0]};
+ char ch{name.front()};
if (isImplicitNoneType_ && respectImplicitNoneType) {
return nullptr;
} else if (auto it{map_.find(ch)}; it != map_.end()) {
@@ -8574,8 +8574,10 @@ bool ResolveNamesVisitor::Pre(const parser::ImportStmt &x) {
} else {
Say(name,
"A distinct '%s' is already present in this scope"_err_en_US)
- .Attach(symbol->name(), "Previous declaration of '%s'"_en_US)
- .Attach(outer->name(), "Declaration of '%s' in host scope"_en_US);
+ .Attach(symbol->name(), "Previous declaration of '%s'"_en_US,
+ symbol->name().ToString())
+ .Attach(outer->name(), "Declaration of '%s' in host scope"_en_US,
+ outer->name().ToString());
}
}
} else {
diff --git a/flang/lib/Semantics/runtime-type-info.cpp b/flang/lib/Semantics/runtime-type-info.cpp
index 51ba21a9e5ed..5916a07df774 100644
--- a/flang/lib/Semantics/runtime-type-info.cpp
+++ b/flang/lib/Semantics/runtime-type-info.cpp
@@ -1131,7 +1131,7 @@ void RuntimeTableBuilder::DescribeSpecialProc(
if (auto proc{evaluate::characteristics::Procedure::Characterize(
specific, context_.foldingContext())}) {
std::uint8_t isArgDescriptorSet{0};
- std::uint8_t isArgContiguousSet{0};
+ bool specialCaseFlag{0};
int argThatMightBeDescriptor{0};
MaybeExpr which;
if (isAssignment) {
@@ -1197,7 +1197,7 @@ void RuntimeTableBuilder::DescribeSpecialProc(
TypeAndShape::Attr::AssumedShape) ||
dummyData.attrs.test(evaluate::characteristics::
DummyDataObject::Attr::Contiguous)) {
- isArgContiguousSet |= 1;
+ specialCaseFlag = true;
}
}
}
@@ -1216,7 +1216,7 @@ void RuntimeTableBuilder::DescribeSpecialProc(
return;
}
if (ddo->type.type().IsPolymorphic()) {
- isArgDescriptorSet |= 1;
+ argThatMightBeDescriptor = 1;
}
switch (io.value()) {
case common::DefinedIo::ReadFormatted:
@@ -1232,6 +1232,9 @@ void RuntimeTableBuilder::DescribeSpecialProc(
which = writeUnformattedEnum_;
break;
}
+ if (context_.defaultKinds().GetDefaultKind(TypeCategory::Integer) == 8) {
+ specialCaseFlag = true; // UNIT= & IOSTAT= INTEGER(8)
+ }
}
if (argThatMightBeDescriptor != 0) {
if (const auto *dummyData{
@@ -1262,8 +1265,8 @@ void RuntimeTableBuilder::DescribeSpecialProc(
}
CHECK(bindingIndex <= 255);
AddValue(values, specialSchema_, "istypebound"s, IntExpr<1>(bindingIndex));
- AddValue(values, specialSchema_, "isargcontiguousset"s,
- IntExpr<1>(isArgContiguousSet));
+ AddValue(values, specialSchema_, "specialcaseflag"s,
+ IntExpr<1>(specialCaseFlag));
AddValue(values, specialSchema_, procCompName,
SomeExpr{evaluate::ProcedureDesignator{specific}});
// index might already be present in the case of an override
@@ -1383,19 +1386,26 @@ CollectNonTbpDefinedIoGenericInterfaces(
} else {
// Local scope's specific overrides host's for this type
bool updated{false};
+ std::uint8_t flags{0};
+ if (declType->IsPolymorphic()) {
+ flags |= IsDtvArgPolymorphic;
+ }
+ if (scope.context().GetDefaultKind(TypeCategory::Integer) ==
+ 8) {
+ flags |= DefinedIoInteger8;
+ }
for (auto [iter, end]{result.equal_range(dtDesc)}; iter != end;
++iter) {
NonTbpDefinedIo &nonTbp{iter->second};
if (nonTbp.definedIo == which) {
nonTbp.subroutine = &*specific;
- nonTbp.isDtvArgPolymorphic = declType->IsPolymorphic();
+ nonTbp.flags = flags;
updated = true;
}
}
if (!updated) {
- result.emplace(dtDesc,
- NonTbpDefinedIo{
- &*specific, which, declType->IsPolymorphic()});
+ result.emplace(
+ dtDesc, NonTbpDefinedIo{&*specific, which, flags});
}
}
}
diff --git a/flang/lib/Semantics/semantics.cpp b/flang/lib/Semantics/semantics.cpp
index ab78605d01f4..b15ed057b52f 100644
--- a/flang/lib/Semantics/semantics.cpp
+++ b/flang/lib/Semantics/semantics.cpp
@@ -376,8 +376,7 @@ const DeclTypeSpec &SemanticsContext::MakeLogicalType(int kind) {
}
bool SemanticsContext::AnyFatalError() const {
- return !messages_.empty() &&
- (warningsAreErrors_ || messages_.AnyFatalError());
+ return messages_.AnyFatalError(warningsAreErrors_);
}
bool SemanticsContext::HasError(const Symbol &symbol) {
return errorSymbols_.count(symbol) > 0;
@@ -658,7 +657,7 @@ void Semantics::EmitMessages(llvm::raw_ostream &os) {
context_.messages().ResolveProvenances(context_.allCookedSources());
context_.messages().Emit(os, context_.allCookedSources(),
/*echoSourceLine=*/true, &context_.languageFeatures(),
- /*maxErrorsToEmit=*/context_.maxErrors());
+ context_.maxErrors(), context_.warningsAreErrors());
}
void SemanticsContext::DumpSymbols(llvm::raw_ostream &os) {
diff --git a/flang/lib/Semantics/tools.cpp b/flang/lib/Semantics/tools.cpp
index d27d250b3f11..5a5b02e1ac3c 100644
--- a/flang/lib/Semantics/tools.cpp
+++ b/flang/lib/Semantics/tools.cpp
@@ -348,9 +348,9 @@ const Symbol &BypassGeneric(const Symbol &symbol) {
const Symbol &GetCrayPointer(const Symbol &crayPointee) {
const Symbol *found{nullptr};
- for (const auto &[pointee, pointer] :
- crayPointee.GetUltimate().owner().crayPointers()) {
- if (pointee == crayPointee.name()) {
+ const Symbol &ultimate{crayPointee.GetUltimate()};
+ for (const auto &[pointee, pointer] : ultimate.owner().crayPointers()) {
+ if (pointee == ultimate.name()) {
found = &pointer.get();
break;
}
@@ -1740,7 +1740,7 @@ std::forward_list<std::string> GetOperatorNames(
std::forward_list<std::string> GetAllNames(
const SemanticsContext &context, const SourceName &name) {
std::string str{name.ToString()};
- if (!name.empty() && name.end()[-1] == ')' &&
+ if (!name.empty() && name.back() == ')' &&
name.ToString().rfind("operator(", 0) == 0) {
for (int i{0}; i != common::LogicalOperator_enumSize; ++i) {
auto names{GetOperatorNames(context, common::LogicalOperator{i})};