forked from OSchip/llvm-project
[flang] Fix missing substring bounds (bug flang-compiler/f18#1091)
Original-commit: flang-compiler/f18@3b0c150b2e Reviewed-on: https://github.com/flang-compiler/f18/pull/1093
This commit is contained in:
parent
b2a0e4a235
commit
84a099df05
|
@ -208,41 +208,52 @@ template<typename A, typename B> A *UnwrapExpr(std::optional<B> &x) {
|
|||
}
|
||||
|
||||
// If an expression simply wraps a DataRef, extract and return it.
|
||||
// The Boolean argument controls the handling of Substring
|
||||
// references: when true (not default), it extracts the base DataRef
|
||||
// of a substring, if it has one.
|
||||
template <typename A>
|
||||
common::IfNoLvalue<std::optional<DataRef>, A> ExtractDataRef(const A &) {
|
||||
common::IfNoLvalue<std::optional<DataRef>, A> ExtractDataRef(
|
||||
const A &, bool intoSubstring) {
|
||||
return std::nullopt; // default base case
|
||||
}
|
||||
template <typename T>
|
||||
std::optional<DataRef> ExtractDataRef(const Designator<T> &d) {
|
||||
std::optional<DataRef> ExtractDataRef(
|
||||
const Designator<T> &d, bool intoSubstring = false) {
|
||||
return std::visit(
|
||||
[](const auto &x) -> std::optional<DataRef> {
|
||||
[=](const auto &x) -> std::optional<DataRef> {
|
||||
if constexpr (common::HasMember<decltype(x), decltype(DataRef::u)>) {
|
||||
return DataRef{x};
|
||||
}
|
||||
if constexpr (std::is_same_v<std::decay_t<decltype(x)>, Substring>) {
|
||||
return ExtractDataRef(x);
|
||||
if (intoSubstring) {
|
||||
return ExtractSubstringBase(x);
|
||||
}
|
||||
}
|
||||
return std::nullopt; // w/o "else" to dodge bogus g++ 8.1 warning
|
||||
},
|
||||
d.u);
|
||||
}
|
||||
template <typename T>
|
||||
std::optional<DataRef> ExtractDataRef(const Expr<T> &expr) {
|
||||
return std::visit([](const auto &x) { return ExtractDataRef(x); }, expr.u);
|
||||
std::optional<DataRef> ExtractDataRef(
|
||||
const Expr<T> &expr, bool intoSubstring = false) {
|
||||
return std::visit(
|
||||
[=](const auto &x) { return ExtractDataRef(x, intoSubstring); }, expr.u);
|
||||
}
|
||||
template <typename A>
|
||||
std::optional<DataRef> ExtractDataRef(const std::optional<A> &x) {
|
||||
std::optional<DataRef> ExtractDataRef(
|
||||
const std::optional<A> &x, bool intoSubstring = false) {
|
||||
if (x) {
|
||||
return ExtractDataRef(*x);
|
||||
return ExtractDataRef(*x, intoSubstring);
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
std::optional<DataRef> ExtractDataRef(const Substring &);
|
||||
std::optional<DataRef> ExtractSubstringBase(const Substring &);
|
||||
|
||||
// Predicate: is an expression is an array element reference?
|
||||
template<typename T> bool IsArrayElement(const Expr<T> &expr) {
|
||||
if (auto dataRef{ExtractDataRef(expr)}) {
|
||||
template <typename T>
|
||||
bool IsArrayElement(const Expr<T> &expr, bool intoSubstring = false) {
|
||||
if (auto dataRef{ExtractDataRef(expr, intoSubstring)}) {
|
||||
const DataRef *ref{&*dataRef};
|
||||
while (const Component * component{std::get_if<Component>(&ref->u)}) {
|
||||
ref = &component->base();
|
||||
|
@ -253,8 +264,9 @@ template<typename T> bool IsArrayElement(const Expr<T> &expr) {
|
|||
}
|
||||
}
|
||||
|
||||
template<typename A> std::optional<NamedEntity> ExtractNamedEntity(const A &x) {
|
||||
if (auto dataRef{ExtractDataRef(x)}) {
|
||||
template <typename A>
|
||||
std::optional<NamedEntity> ExtractNamedEntity(const A &x) {
|
||||
if (auto dataRef{ExtractDataRef(x, true)}) {
|
||||
return std::visit(
|
||||
common::visitors{
|
||||
[](SymbolRef &&symbol) -> std::optional<NamedEntity> {
|
||||
|
@ -310,7 +322,7 @@ struct ExtractCoindexedObjectHelper {
|
|||
};
|
||||
|
||||
template <typename A> std::optional<CoarrayRef> ExtractCoarrayRef(const A &x) {
|
||||
if (auto dataRef{ExtractDataRef(x)}) {
|
||||
if (auto dataRef{ExtractDataRef(x, true)}) {
|
||||
return ExtractCoindexedObjectHelper{}(*dataRef);
|
||||
} else {
|
||||
return ExtractCoindexedObjectHelper{}(x);
|
||||
|
@ -330,7 +342,7 @@ template<typename A> const Symbol *UnwrapWholeSymbolDataRef(const A &x) {
|
|||
|
||||
// GetFirstSymbol(A%B%C[I]%D) -> A
|
||||
template <typename A> const Symbol *GetFirstSymbol(const A &x) {
|
||||
if (auto dataRef{ExtractDataRef(x)}) {
|
||||
if (auto dataRef{ExtractDataRef(x, true)}) {
|
||||
return &dataRef->GetFirstSymbol();
|
||||
} else {
|
||||
return nullptr;
|
||||
|
@ -769,7 +781,8 @@ template<typename T>
|
|||
std::optional<BaseObject> GetBaseObject(const Designator<T> &x) {
|
||||
return x.GetBaseObject();
|
||||
}
|
||||
template<typename T> std::optional<BaseObject> GetBaseObject(const Expr<T> &x) {
|
||||
template <typename T>
|
||||
std::optional<BaseObject> GetBaseObject(const Expr<T> &x) {
|
||||
return std::visit([](const auto &y) { return GetBaseObject(y); }, x.u);
|
||||
}
|
||||
template <typename A>
|
||||
|
@ -851,5 +864,5 @@ std::optional<std::string> FindImpureCall(
|
|||
std::optional<std::string> FindImpureCall(
|
||||
const IntrinsicProcTable &, const ProcedureRef &);
|
||||
|
||||
}
|
||||
} // namespace Fortran::evaluate
|
||||
#endif // FORTRAN_EVALUATE_TOOLS_H_
|
||||
|
|
|
@ -38,7 +38,7 @@ Expr<SomeType> Parenthesize(Expr<SomeType> &&expr) {
|
|||
std::move(expr.u));
|
||||
}
|
||||
|
||||
std::optional<DataRef> ExtractDataRef(const Substring &substring) {
|
||||
std::optional<DataRef> ExtractSubstringBase(const Substring &substring) {
|
||||
return std::visit(
|
||||
common::visitors{
|
||||
[&](const DataRef &x) -> std::optional<DataRef> { return x; },
|
||||
|
@ -872,4 +872,4 @@ std::optional<std::string> FindImpureCall(
|
|||
return FindImpureCallHelper{intrinsics}(proc);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Fortran::evaluate
|
||||
|
|
|
@ -178,7 +178,7 @@ bool AssignmentContext::CheckForPureContext(const SomeExpr &lhs,
|
|||
"A pure subprogram may not define a coindexed object"_err_en_US);
|
||||
} else if (const Symbol * base{GetFirstSymbol(lhs)}) {
|
||||
if (const auto *assoc{base->detailsIf<AssocEntityDetails>()}) {
|
||||
auto dataRef{ExtractDataRef(assoc->expr())};
|
||||
auto dataRef{ExtractDataRef(assoc->expr(), true)};
|
||||
// ASSOCIATE(a=>x) -- check x, not a, for "a=..."
|
||||
base = dataRef ? &dataRef->GetFirstSymbol() : nullptr;
|
||||
}
|
||||
|
@ -291,6 +291,6 @@ void AssignmentChecker::Leave(const parser::MaskedElsewhereStmt &) {
|
|||
context_.value().PopWhereContext();
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Fortran::semantics
|
||||
template class Fortran::common::Indirection<
|
||||
Fortran::semantics::AssignmentContext>;
|
||||
|
|
|
@ -135,7 +135,8 @@ public:
|
|||
: context_{context}, allowAssumedType_{false} {}
|
||||
ArgumentAnalyzer(ExpressionAnalyzer &context, parser::CharBlock source,
|
||||
bool allowAssumedType = false)
|
||||
: context_{context}, source_{source}, allowAssumedType_{allowAssumedType} {}
|
||||
: context_{context}, source_{source}, allowAssumedType_{
|
||||
allowAssumedType} {}
|
||||
bool fatalErrors() const { return fatalErrors_; }
|
||||
ActualArguments &&GetActuals() {
|
||||
CHECK(!fatalErrors_);
|
||||
|
@ -355,6 +356,8 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::Designator &d) {
|
|||
FixMisparsedSubstring(d);
|
||||
// These checks have to be deferred to these "top level" data-refs where
|
||||
// we can be sure that there are no following subscripts (yet).
|
||||
// Substrings have already been run through TopLevelChecks() and
|
||||
// won't be returned by ExtractDataRef().
|
||||
if (MaybeExpr result{Analyze(d.u)}) {
|
||||
if (std::optional<DataRef> dataRef{ExtractDataRef(std::move(result))}) {
|
||||
return TopLevelChecks(std::move(*dataRef));
|
||||
|
@ -519,10 +522,17 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::RealLiteralConstant &x) {
|
|||
if (parser::IsLetter(*p)) {
|
||||
expoLetter = *p;
|
||||
switch (expoLetter) {
|
||||
case 'e': letterKind = defaults.GetDefaultKind(TypeCategory::Real); break;
|
||||
case 'd': letterKind = defaults.doublePrecisionKind(); break;
|
||||
case 'q': letterKind = defaults.quadPrecisionKind(); break;
|
||||
default: Say("Unknown exponent letter '%c'"_err_en_US, expoLetter);
|
||||
case 'e':
|
||||
letterKind = defaults.GetDefaultKind(TypeCategory::Real);
|
||||
break;
|
||||
case 'd':
|
||||
letterKind = defaults.doublePrecisionKind();
|
||||
break;
|
||||
case 'q':
|
||||
letterKind = defaults.quadPrecisionKind();
|
||||
break;
|
||||
default:
|
||||
Say("Unknown exponent letter '%c'"_err_en_US, expoLetter);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -599,7 +609,8 @@ MaybeExpr ExpressionAnalyzer::AnalyzeString(std::string &&string, int kind) {
|
|||
return AsGenericExpr(Constant<Type<TypeCategory::Character, 4>>{
|
||||
parser::DecodeString<std::u32string, parser::Encoding::UTF_8>(
|
||||
string, true)});
|
||||
default: CRASH_NO_CASE;
|
||||
default:
|
||||
CRASH_NO_CASE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -636,11 +647,18 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::BOZLiteralConstant &x) {
|
|||
const char *p{x.v.c_str()};
|
||||
std::uint64_t base{16};
|
||||
switch (*p++) {
|
||||
case 'b': base = 2; break;
|
||||
case 'o': base = 8; break;
|
||||
case 'z': break;
|
||||
case 'x': break;
|
||||
default: CRASH_NO_CASE;
|
||||
case 'b':
|
||||
base = 2;
|
||||
break;
|
||||
case 'o':
|
||||
base = 8;
|
||||
break;
|
||||
case 'z':
|
||||
break;
|
||||
case 'x':
|
||||
break;
|
||||
default:
|
||||
CRASH_NO_CASE;
|
||||
}
|
||||
CHECK(*p == '"');
|
||||
++p;
|
||||
|
@ -3024,4 +3042,4 @@ bool ExprChecker::Pre(const parser::DataStmtConstant &x) {
|
|||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Fortran::semantics
|
||||
|
|
|
@ -56,8 +56,10 @@ const Scope *FindProgramUnitContaining(const Scope &start) {
|
|||
case Scope::Kind::Module:
|
||||
case Scope::Kind::MainProgram:
|
||||
case Scope::Kind::Subprogram:
|
||||
case Scope::Kind::BlockData: return true;
|
||||
default: return false;
|
||||
case Scope::Kind::BlockData:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -412,7 +414,8 @@ bool ExprTypeKindIsDefault(
|
|||
}
|
||||
|
||||
// If an analyzed expr or assignment is missing, dump the node and die.
|
||||
template<typename T> static void CheckMissingAnalysis(bool absent, const T &x) {
|
||||
template <typename T>
|
||||
static void CheckMissingAnalysis(bool absent, const T &x) {
|
||||
if (absent) {
|
||||
std::string buf;
|
||||
llvm::raw_string_ostream ss{buf};
|
||||
|
@ -816,7 +819,7 @@ std::optional<parser::Message> WhyNotModifiable(parser::CharBlock at,
|
|||
const SomeExpr &expr, const Scope &scope, bool vectorSubscriptIsOk) {
|
||||
if (!evaluate::IsVariable(expr)) {
|
||||
return parser::Message{at, "Expression is not a variable"_en_US};
|
||||
} else if (auto dataRef{evaluate::ExtractDataRef(expr)}) {
|
||||
} else if (auto dataRef{evaluate::ExtractDataRef(expr, true)}) {
|
||||
if (!vectorSubscriptIsOk && evaluate::HasVectorSubscript(expr)) {
|
||||
return parser::Message{at, "Variable has a vector subscript"_en_US};
|
||||
}
|
||||
|
@ -1353,4 +1356,4 @@ void LabelEnforce::SayWithConstruct(SemanticsContext &context,
|
|||
context.Say(stmtLocation, message)
|
||||
.Attach(constructLocation, GetEnclosingConstructMsg());
|
||||
}
|
||||
}
|
||||
} // namespace Fortran::semantics
|
||||
|
|
Loading…
Reference in New Issue