void SayAlreadyDeclared(const SourceName &, Symbol &);
void SayAlreadyDeclared(const SourceName &, const SourceName &);
void SayWithReason(
- const parser::Name &, Symbol &, MessageFixedText &&, MessageFixedText &&);
+ const parser::Name &, Symbol &, MessageFixedText &&, Message &&);
void SayWithDecl(const parser::Name &, Symbol &, MessageFixedText &&);
void SayLocalMustBeVariable(const parser::Name &, Symbol &);
void SayDerivedType(const SourceName &, MessageFixedText &&, const Scope &);
}
void ScopeHandler::SayWithReason(const parser::Name &name, Symbol &symbol,
- MessageFixedText &&msg1, MessageFixedText &&msg2) {
- Say2(name, std::move(msg1), symbol, std::move(msg2));
+ MessageFixedText &&msg1, Message &&msg2) {
+ Say(name, std::move(msg1), symbol.name()).Attach(std::move(msg2));
context().SetError(symbol, msg1.isFatal());
}
void ScopeHandler::SayWithDecl(
const parser::Name &name, Symbol &symbol, MessageFixedText &&msg) {
- SayWithReason(name, symbol, std::move(msg),
- symbol.test(Symbol::Flag::Implicit) ? "Implicit declaration of '%s'"_en_US
- : "Declaration of '%s'"_en_US);
+ Say(name, std::move(msg), symbol.name())
+ .Attach(Message{name.source,
+ symbol.test(Symbol::Flag::Implicit)
+ ? "Implicit declaration of '%s'"_en_US
+ : "Declaration of '%s'"_en_US,
+ name.source});
+ context().SetError(symbol, msg.isFatal());
}
void ScopeHandler::SayLocalMustBeVariable(
"Assumed size array '%s' not allowed in a locality-spec"_err_en_US);
return false;
}
- if (std::optional<MessageFixedText> msg{
- WhyNotModifiable(symbol, currScope())}) {
+ if (std::optional<Message> msg{WhyNotModifiable(symbol, currScope())}) {
SayWithReason(name, symbol,
"'%s' may not appear in a locality-spec because it is not "
"definable"_err_en_US,
// C1101 and C1158
// Modifiability checks on the leftmost symbol ("base object")
// of a data-ref
-std::optional<parser::MessageFixedText> WhyNotModifiableFirst(
- const Symbol &symbol, const Scope &scope) {
- if (symbol.has<AssocEntityDetails>()) {
- return "'%s' is construct associated with an expression"_en_US;
+static std::optional<parser::Message> WhyNotModifiableFirst(
+ parser::CharBlock at, const Symbol &symbol, const Scope &scope) {
+ if (const auto *assoc{symbol.detailsIf<AssocEntityDetails>()}) {
+ if (assoc->rank().has_value()) {
+ return std::nullopt; // SELECT RANK always modifiable variable
+ } else if (IsVariable(assoc->expr())) {
+ if (evaluate::HasVectorSubscript(assoc->expr().value())) {
+ return parser::Message{
+ at, "Construct association has a vector subscript"_en_US};
+ } else {
+ return WhyNotModifiable(at, *assoc->expr(), scope);
+ }
+ } else {
+ return parser::Message{at,
+ "'%s' is construct associated with an expression"_en_US,
+ symbol.name()};
+ }
} else if (IsExternalInPureContext(symbol, scope)) {
- return "'%s' is externally visible and referenced in a pure"
- " procedure"_en_US;
+ return parser::Message{at,
+ "'%s' is externally visible and referenced in a pure"
+ " procedure"_en_US,
+ symbol.name()};
} else if (!IsVariableName(symbol)) {
- return "'%s' is not a variable"_en_US;
+ return parser::Message{at, "'%s' is not a variable"_en_US, symbol.name()};
} else {
return std::nullopt;
}
}
// Modifiability checks on the rightmost symbol of a data-ref
-std::optional<parser::MessageFixedText> WhyNotModifiableLast(
- const Symbol &symbol, const Scope &scope) {
+static std::optional<parser::Message> WhyNotModifiableLast(
+ parser::CharBlock at, const Symbol &symbol, const Scope &scope) {
if (IsOrContainsEventOrLockComponent(symbol)) {
- return "'%s' is an entity with either an EVENT_TYPE or LOCK_TYPE"_en_US;
+ return parser::Message{at,
+ "'%s' is an entity with either an EVENT_TYPE or LOCK_TYPE"_en_US,
+ symbol.name()};
} else {
return std::nullopt;
}
// Modifiability checks on the leftmost (base) symbol of a data-ref
// that apply only when there are no pointer components or a base
// that is a pointer.
-std::optional<parser::MessageFixedText> WhyNotModifiableIfNoPtr(
- const Symbol &symbol, const Scope &scope) {
+static std::optional<parser::Message> WhyNotModifiableIfNoPtr(
+ parser::CharBlock at, const Symbol &symbol, const Scope &scope) {
if (InProtectedContext(symbol, scope)) {
- return "'%s' is protected in this scope"_en_US;
+ return parser::Message{
+ at, "'%s' is protected in this scope"_en_US, symbol.name()};
} else if (IsIntentIn(symbol)) {
- return "'%s' is an INTENT(IN) dummy argument"_en_US;
+ return parser::Message{
+ at, "'%s' is an INTENT(IN) dummy argument"_en_US, symbol.name()};
} else {
return std::nullopt;
}
}
// Apply all modifiability checks to a single symbol
-std::optional<parser::MessageFixedText> WhyNotModifiable(
+std::optional<parser::Message> WhyNotModifiable(
const Symbol &original, const Scope &scope) {
const Symbol &symbol{GetAssociationRoot(original)};
- if (auto first{WhyNotModifiableFirst(symbol, scope)}) {
+ if (auto first{WhyNotModifiableFirst(symbol.name(), symbol, scope)}) {
return first;
- } else if (auto last{WhyNotModifiableLast(symbol, scope)}) {
+ } else if (auto last{WhyNotModifiableLast(symbol.name(), symbol, scope)}) {
return last;
} else if (!IsPointer(symbol)) {
- return WhyNotModifiableIfNoPtr(symbol, scope);
+ return WhyNotModifiableIfNoPtr(symbol.name(), symbol, scope);
} else {
return std::nullopt;
}
return parser::Message{at, "Variable has a vector subscript"_en_US};
}
const Symbol &first{GetAssociationRoot(dataRef->GetFirstSymbol())};
- if (auto maybeWhyFirst{WhyNotModifiableFirst(first, scope)}) {
- return parser::Message{first.name(),
- parser::MessageFormattedText{
- std::move(*maybeWhyFirst), first.name()}};
+ if (auto maybeWhyFirst{WhyNotModifiableFirst(at, first, scope)}) {
+ return maybeWhyFirst;
}
const Symbol &last{dataRef->GetLastSymbol()};
- if (auto maybeWhyLast{WhyNotModifiableLast(last, scope)}) {
- return parser::Message{last.name(),
- parser::MessageFormattedText{std::move(*maybeWhyLast), last.name()}};
+ if (auto maybeWhyLast{WhyNotModifiableLast(at, last, scope)}) {
+ return maybeWhyLast;
}
if (!GetLastPointerSymbol(*dataRef)) {
- if (auto maybeWhyFirst{WhyNotModifiableIfNoPtr(first, scope)}) {
- return parser::Message{first.name(),
- parser::MessageFormattedText{
- std::move(*maybeWhyFirst), first.name()}};
+ if (auto maybeWhyFirst{WhyNotModifiableIfNoPtr(at, first, scope)}) {
+ return maybeWhyFirst;
}
}
} else if (!evaluate::IsVariable(expr)) {