forked from OSchip/llvm-project
[flang] Resolve misparse of structure constructor as function reference.
Original-commit: flang-compiler/f18@5b6b2540f6 Reviewed-on: https://github.com/flang-compiler/f18/pull/322 Tree-same-pre-rewrite: false
This commit is contained in:
parent
bc409369c2
commit
64ea462e3a
|
@ -89,34 +89,50 @@ static Designator MakeArrayElementRef(Name &name, std::list<Expr> &subscripts) {
|
|||
return Designator{DataRef{common::Indirection{std::move(arrayElement)}}};
|
||||
}
|
||||
|
||||
static std::optional<Expr> ActualArgToExpr(ActualArgSpec &arg) {
|
||||
return std::visit(
|
||||
common::visitors{
|
||||
[&](common::Indirection<Expr> &y) {
|
||||
return std::make_optional<Expr>(std::move(y.value()));
|
||||
},
|
||||
[&](common::Indirection<Variable> &y) {
|
||||
return std::visit(
|
||||
[&](auto &indirection) {
|
||||
return std::make_optional<Expr>(
|
||||
std::move(indirection.value()));
|
||||
},
|
||||
y.value().u);
|
||||
},
|
||||
[&](auto &) -> std::optional<Expr> { return std::nullopt; },
|
||||
},
|
||||
std::get<ActualArg>(arg.t).u);
|
||||
}
|
||||
|
||||
Designator FunctionReference::ConvertToArrayElementRef() {
|
||||
auto &name{std::get<parser::Name>(std::get<ProcedureDesignator>(v.t).u)};
|
||||
std::list<Expr> args;
|
||||
for (auto &arg : std::get<std::list<ActualArgSpec>>(v.t)) {
|
||||
std::visit(
|
||||
common::visitors{
|
||||
[&](common::Indirection<Expr> &y) {
|
||||
args.push_back(std::move(y.value()));
|
||||
},
|
||||
[&](common::Indirection<Variable> &y) {
|
||||
args.push_back(std::visit(
|
||||
common::visitors{
|
||||
[&](common::Indirection<Designator> &z) {
|
||||
return Expr{std::move(z.value())};
|
||||
},
|
||||
[&](common::Indirection<FunctionReference> &z) {
|
||||
return Expr{std::move(z.value())};
|
||||
},
|
||||
},
|
||||
y.value().u));
|
||||
},
|
||||
[&](auto &) { CHECK(!"unexpected kind of ActualArg"); },
|
||||
},
|
||||
std::get<ActualArg>(arg.t).u);
|
||||
args.emplace_back(std::move(ActualArgToExpr(arg).value()));
|
||||
}
|
||||
return MakeArrayElementRef(name, args);
|
||||
}
|
||||
|
||||
StructureConstructor FunctionReference::ConvertToStructureConstructor() {
|
||||
Name name{std::get<parser::Name>(std::get<ProcedureDesignator>(v.t).u)};
|
||||
std::list<ComponentSpec> components;
|
||||
for (auto &arg : std::get<std::list<ActualArgSpec>>(v.t)) {
|
||||
std::optional<Keyword> keyword;
|
||||
if (auto &kw{std::get<std::optional<Keyword>>(arg.t)}) {
|
||||
keyword.emplace(Keyword{Name{kw->v}});
|
||||
}
|
||||
components.emplace_back(
|
||||
std::move(keyword), ComponentDataSource{ActualArgToExpr(arg).value()});
|
||||
}
|
||||
return StructureConstructor{
|
||||
DerivedTypeSpec{std::move(name), std::list<TypeParamSpec>{}},
|
||||
std::move(components)};
|
||||
}
|
||||
|
||||
// R1544 stmt-function-stmt
|
||||
// Convert this stmt-function-stmt to an array element assignment statement.
|
||||
Statement<ActionStmt> StmtFunctionStmt::ConvertToAssignment() {
|
||||
|
|
|
@ -538,8 +538,6 @@ WRAPPER_CLASS(Program, std::list<ProgramUnit>);
|
|||
|
||||
// R603 name -> letter [alphanumeric-character]...
|
||||
struct Name {
|
||||
Name() {}
|
||||
COPY_AND_ASSIGN_BOILERPLATE(Name);
|
||||
std::string ToString() const { return source.ToString(); }
|
||||
CharBlock source;
|
||||
mutable semantics::Symbol *symbol{nullptr}; // filled in during semantics
|
||||
|
@ -3094,6 +3092,7 @@ struct Call {
|
|||
struct FunctionReference {
|
||||
WRAPPER_CLASS_BOILERPLATE(FunctionReference, Call);
|
||||
Designator ConvertToArrayElementRef();
|
||||
StructureConstructor ConvertToStructureConstructor();
|
||||
};
|
||||
|
||||
// R1521 call-stmt -> CALL procedure-designator [( [actual-arg-spec-list] )]
|
||||
|
|
|
@ -196,7 +196,8 @@ MaybeExpr TypedWrapper(const DynamicType &dyType, WRAPPED &&x) {
|
|||
|
||||
// Wraps a data reference in a typed Designator<>.
|
||||
static MaybeExpr Designate(DataRef &&ref) {
|
||||
if (std::optional<DynamicType> dyType{GetSymbolType(ref.GetLastSymbol())}) {
|
||||
if (std::optional<DynamicType> dyType{
|
||||
GetSymbolType(ref.GetLastSymbol().GetUltimate())}) {
|
||||
return TypedWrapper<Designator, DataRef>(
|
||||
std::move(*dyType), std::move(ref));
|
||||
}
|
||||
|
@ -205,7 +206,8 @@ static MaybeExpr Designate(DataRef &&ref) {
|
|||
}
|
||||
|
||||
// Catch and resolve the ambiguous parse of a substring reference
|
||||
// that looks like a 1-D array element or section.
|
||||
// that looks like a 1-D array element or section. The parse tree is
|
||||
// not adjusted.
|
||||
static MaybeExpr ResolveAmbiguousSubstring(ArrayRef &&ref) {
|
||||
if (std::optional<DynamicType> dyType{GetSymbolType(ref.GetLastSymbol())}) {
|
||||
if (dyType->category == TypeCategory::Character && ref.size() == 1) {
|
||||
|
@ -240,7 +242,7 @@ static MaybeExpr ResolveAmbiguousSubstring(ArrayRef &&ref) {
|
|||
// ambiguous parse of a substring reference that looks like a 1-D array
|
||||
// element or section.
|
||||
MaybeExpr ExpressionAnalyzer::CompleteSubscripts(ArrayRef &&ref) {
|
||||
const Symbol &symbol{ref.GetLastSymbol()};
|
||||
const Symbol &symbol{ref.GetLastSymbol().GetUltimate()};
|
||||
int symbolRank{symbol.Rank()};
|
||||
int subscripts = ref.size();
|
||||
if (subscripts == 0) {
|
||||
|
@ -627,23 +629,24 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::Name &n) {
|
|||
if (std::optional<int> kind{IsAcImpliedDo(n.source)}) {
|
||||
return AsMaybeExpr(ConvertToKind<TypeCategory::Integer>(
|
||||
*kind, AsExpr(ImpliedDoIndex{n.source})));
|
||||
} else if (n.symbol == nullptr) {
|
||||
// error should have been reported in name resolution
|
||||
} else if (n.symbol->attrs().test(semantics::Attr::PARAMETER)) {
|
||||
if (auto *details{n.symbol->detailsIf<semantics::ObjectEntityDetails>()}) {
|
||||
if (auto &init{details->init()}) {
|
||||
return init;
|
||||
} else if (n.symbol != nullptr) {
|
||||
const Symbol &ultimate{n.symbol->GetUltimate()};
|
||||
if (ultimate.attrs().test(semantics::Attr::PARAMETER)) {
|
||||
if (auto *details{ultimate.detailsIf<semantics::ObjectEntityDetails>()}) {
|
||||
if (auto &init{details->init()}) {
|
||||
return init;
|
||||
}
|
||||
}
|
||||
// TODO: enumerators, do they have the PARAMETER attribute?
|
||||
} else if (ultimate.detailsIf<semantics::TypeParamDetails>()) {
|
||||
// A bare reference to a derived type parameter (within a parameterized
|
||||
// derived type definition)
|
||||
return AsMaybeExpr(MakeTypeParamInquiry(&ultimate));
|
||||
} else if (MaybeExpr result{Designate(DataRef{*n.symbol})}) {
|
||||
return result;
|
||||
} else {
|
||||
Say(n.source, "not of a supported type and kind"_err_en_US);
|
||||
}
|
||||
// TODO: enumerators, do they have the PARAMETER attribute?
|
||||
} else if (n.symbol->detailsIf<semantics::TypeParamDetails>()) {
|
||||
// A bare reference to a derived type parameter (within a parameterized
|
||||
// derived type definition)
|
||||
return AsMaybeExpr(MakeTypeParamInquiry(n.symbol));
|
||||
} else if (MaybeExpr result{Designate(DataRef{*n.symbol})}) {
|
||||
return result;
|
||||
} else {
|
||||
Say(n.source, "not of a supported type and kind"_err_en_US);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
@ -1382,38 +1385,31 @@ auto ExpressionAnalyzer::Procedure(const parser::ProcedureDesignator &pd,
|
|||
n.ToString().data());
|
||||
return std::nullopt;
|
||||
}
|
||||
return std::visit(
|
||||
common::visitors{
|
||||
[&](const semantics::ProcEntityDetails &p)
|
||||
-> std::optional<CallAndArguments> {
|
||||
if (p.HasExplicitInterface()) {
|
||||
// TODO: check actual arguments vs. interface
|
||||
} else {
|
||||
CallCharacteristics cc{n.source};
|
||||
if (std::optional<SpecificCall> specificCall{
|
||||
context().intrinsics().Probe(
|
||||
cc, arguments, &GetContextualMessages())}) {
|
||||
return {CallAndArguments{
|
||||
ProcedureDesignator{
|
||||
std::move(specificCall->specificIntrinsic)},
|
||||
std::move(specificCall->arguments)}};
|
||||
} else {
|
||||
// TODO: if name is not INTRINSIC, call with implicit
|
||||
// interface
|
||||
}
|
||||
}
|
||||
return {CallAndArguments{ProcedureDesignator{*n.symbol},
|
||||
std::move(arguments)}};
|
||||
},
|
||||
[&](const auto &) -> std::optional<CallAndArguments> {
|
||||
// TODO pmk WIP: resolve ambiguous array reference or
|
||||
// structure constructor usage that reach here
|
||||
Say("TODO: unimplemented/invalid kind of symbol as procedure designator '%s'"_err_en_US,
|
||||
n.ToString().data());
|
||||
return std::nullopt;
|
||||
},
|
||||
},
|
||||
n.symbol->details());
|
||||
const Symbol &ultimate{n.symbol->GetUltimate()};
|
||||
if (const auto *proc{
|
||||
ultimate.detailsIf<semantics::ProcEntityDetails>()}) {
|
||||
if (proc->HasExplicitInterface()) {
|
||||
// TODO: check actual arguments vs. interface
|
||||
} else {
|
||||
CallCharacteristics cc{n.source};
|
||||
if (std::optional<SpecificCall> specificCall{
|
||||
context().intrinsics().Probe(
|
||||
cc, arguments, &GetContextualMessages())}) {
|
||||
return {
|
||||
CallAndArguments{ProcedureDesignator{std::move(
|
||||
specificCall->specificIntrinsic)},
|
||||
std::move(specificCall->arguments)}};
|
||||
} else {
|
||||
// TODO: if name is not INTRINSIC, call with implicit
|
||||
// interface
|
||||
}
|
||||
}
|
||||
return {CallAndArguments{
|
||||
ProcedureDesignator{*n.symbol}, std::move(arguments)}};
|
||||
} else {
|
||||
Say(n.source, "not a procedure"_err_en_US);
|
||||
return std::nullopt;
|
||||
}
|
||||
},
|
||||
[&](const parser::ProcComponentRef &pcr)
|
||||
-> std::optional<CallAndArguments> {
|
||||
|
@ -1756,21 +1752,60 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::DefinedBinary &) {
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Converts, if appropriate, a misparse of the ambiguous syntax A(1) as
|
||||
// a function reference into an array reference or a structure constructor.
|
||||
template<typename... A>
|
||||
void FixMisparsedFunctionReference(const std::variant<A...> &constU) {
|
||||
// The parse tree is updated in situ when resolving an ambiguous parse.
|
||||
using uType = std::decay_t<decltype(constU)>;
|
||||
auto &u{const_cast<uType &>(constU)};
|
||||
if (auto *func{
|
||||
std::get_if<common::Indirection<parser::FunctionReference>>(&u)}) {
|
||||
parser::FunctionReference &funcRef{func->value()};
|
||||
auto &proc{std::get<parser::ProcedureDesignator>(funcRef.v.t)};
|
||||
if (auto *name{std::get_if<parser::Name>(&proc.u)}) {
|
||||
if (name->symbol == nullptr) {
|
||||
return;
|
||||
}
|
||||
Symbol &symbol{name->symbol->GetUltimate()};
|
||||
if constexpr (common::HasMember<common::Indirection<parser::Designator>,
|
||||
uType>) {
|
||||
if (symbol.has<semantics::ObjectEntityDetails>()) {
|
||||
u = common::Indirection{funcRef.ConvertToArrayElementRef()};
|
||||
return;
|
||||
// N.B. Expression semantics will reinterpret an array element
|
||||
// reference as a single-character substring elsewhere if necessary.
|
||||
}
|
||||
}
|
||||
if constexpr (common::HasMember<StructureConstructor, uType>) {
|
||||
if (symbol.has<semantics::DerivedTypeDetails>()) {
|
||||
u = funcRef.ConvertToStructureConstructor();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr &expr) {
|
||||
if (expr.typedExpr.has_value()) {
|
||||
// Expression was already checked by ExprChecker
|
||||
return std::make_optional<Expr<SomeType>>(expr.typedExpr.value().v);
|
||||
} else if (!expr.source.empty()) {
|
||||
// Analyze the expression in a specified source position context for better
|
||||
// error reporting.
|
||||
auto save{GetFoldingContext().messages().SetLocation(expr.source)};
|
||||
return Analyze(expr.u);
|
||||
} else {
|
||||
return Analyze(expr.u);
|
||||
FixMisparsedFunctionReference(expr.u);
|
||||
if (!expr.source.empty()) {
|
||||
// Analyze the expression in a specified source position context for
|
||||
// better error reporting.
|
||||
auto save{GetFoldingContext().messages().SetLocation(expr.source)};
|
||||
return Analyze(expr.u);
|
||||
} else {
|
||||
return Analyze(expr.u);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MaybeExpr ExpressionAnalyzer::Analyze(const parser::Variable &variable) {
|
||||
FixMisparsedFunctionReference(variable.u);
|
||||
return Analyze(variable.u);
|
||||
}
|
||||
|
||||
|
@ -1894,4 +1929,19 @@ void ExprChecker::Enter(const parser::Expr &expr) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ExprChecker::Enter(const parser::Variable &var) {
|
||||
#if PMKDEBUG
|
||||
if (MaybeExpr checked{AnalyzeExpr(context_, var)}) {
|
||||
// checked->AsFortran(std::cout << "checked variable: ") << '\n';
|
||||
#else
|
||||
if (AnalyzeExpr(context_, var)) {
|
||||
#endif
|
||||
} else {
|
||||
#if PMKDEBUG
|
||||
std::cout << "TODO: expression analysis failed for this variable: ";
|
||||
DumpTree(std::cout, var);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -297,6 +297,7 @@ class ExprChecker : public virtual BaseChecker {
|
|||
public:
|
||||
explicit ExprChecker(SemanticsContext &context) : context_{context} {}
|
||||
void Enter(const parser::Expr &);
|
||||
void Enter(const parser::Variable &);
|
||||
|
||||
private:
|
||||
SemanticsContext &context_;
|
||||
|
|
|
@ -37,8 +37,6 @@ public:
|
|||
void Post(parser::Name &);
|
||||
void Post(parser::SpecificationPart &);
|
||||
bool Pre(parser::ExecutionPart &);
|
||||
void Post(parser::Variable &x) { ConvertFunctionRef(x); }
|
||||
void Post(parser::Expr &x) { ConvertFunctionRef(x); }
|
||||
|
||||
// Name resolution yet implemented:
|
||||
bool Pre(parser::EquivalenceStmt &) { return false; }
|
||||
|
@ -62,24 +60,6 @@ private:
|
|||
bool errorOnUnresolvedName_{true};
|
||||
parser::Messages &messages_;
|
||||
std::list<stmtFuncType> stmtFuncsToConvert_;
|
||||
|
||||
// For T = Variable or Expr, if x has a function reference that really
|
||||
// should be an array element reference (i.e. the name occurs in an
|
||||
// entity declaration, convert it.
|
||||
template<typename T> void ConvertFunctionRef(T &x) {
|
||||
auto *funcRef{
|
||||
std::get_if<common::Indirection<parser::FunctionReference>>(&x.u)};
|
||||
if (!funcRef) {
|
||||
return;
|
||||
}
|
||||
parser::Name *name{std::get_if<parser::Name>(
|
||||
&std::get<parser::ProcedureDesignator>(funcRef->value().v.t).u)};
|
||||
if (!name || !name->symbol ||
|
||||
!name->symbol->GetUltimate().has<ObjectEntityDetails>()) {
|
||||
return;
|
||||
}
|
||||
x.u = common::Indirection{funcRef->value().ConvertToArrayElementRef()};
|
||||
}
|
||||
};
|
||||
|
||||
// Check that name has been resolved to a symbol
|
||||
|
|
Loading…
Reference in New Issue