Index: flang/include/flang/Evaluate/call.h =================================================================== --- flang/include/flang/Evaluate/call.h +++ flang/include/flang/Evaluate/call.h @@ -130,6 +130,13 @@ dummyIntent_ = intent; return *this; } + std::optional sourceLocation() const { + return sourceLocation_; + } + ActualArgument &set_sourceLocation(std::optional at) { + sourceLocation_ = at; + return *this; + } // Wrap this argument in parentheses void Parenthesize(); @@ -148,6 +155,7 @@ std::optional keyword_; bool isPassedObject_{false}; common::Intent dummyIntent_{common::Intent::Default}; + std::optional sourceLocation_; }; using ActualArguments = std::vector>; Index: flang/lib/Semantics/check-call.cpp =================================================================== --- flang/lib/Semantics/check-call.cpp +++ flang/lib/Semantics/check-call.cpp @@ -26,6 +26,8 @@ static void CheckImplicitInterfaceArg( evaluate::ActualArgument &arg, parser::ContextualMessages &messages) { + auto restorer{ + messages.SetLocation(arg.sourceLocation().value_or(messages.at()))}; if (auto kw{arg.keyword()}) { messages.Say(*kw, "Keyword '%s=' may not appear in a reference to a procedure with an implicit interface"_err_en_US, @@ -525,6 +527,8 @@ const characteristics::DummyProcedure &dummy, const std::string &dummyName, evaluate::FoldingContext &context) { parser::ContextualMessages &messages{context.messages()}; + auto restorer{ + messages.SetLocation(arg.sourceLocation().value_or(messages.at()))}; const characteristics::Procedure &interface { dummy.procedure.value() }; if (const auto *expr{arg.UnwrapExpr()}) { bool dummyIsPointer{ @@ -658,6 +662,8 @@ if (!dummy.name.empty()) { dummyName += " '"s + parser::ToLowerCaseLetters(dummy.name) + "='"; } + auto restorer{ + messages.SetLocation(arg.sourceLocation().value_or(messages.at()))}; std::visit( common::visitors{ [&](const characteristics::DummyDataObject &object) { Index: flang/lib/Semantics/expression.cpp =================================================================== --- flang/lib/Semantics/expression.cpp +++ flang/lib/Semantics/expression.cpp @@ -92,6 +92,24 @@ return std::nullopt; } +// Utilities to set a source location, if we have one, on an actual argument, +// when it is statically present. +static void SetArgSourceLocation(ActualArgument &x, parser::CharBlock at) { + x.set_sourceLocation(at); +} +static void SetArgSourceLocation( + std::optional &x, parser::CharBlock at) { + if (x) { + x->set_sourceLocation(at); + } +} +static void SetArgSourceLocation( + std::optional &x, std::optional at) { + if (x && at) { + x->set_sourceLocation(*at); + } +} + class ArgumentAnalyzer { public: explicit ArgumentAnalyzer(ExpressionAnalyzer &context) @@ -116,6 +134,7 @@ } void Analyze(const parser::Expr &x) { actuals_.emplace_back(AnalyzeExpr(x)); + SetArgSourceLocation(actuals_.back(), x.source); fatalErrors_ |= !actuals_.back(); } void Analyze(const parser::Variable &); @@ -1072,8 +1091,9 @@ } else if (kind == MiscKind::KindParamInquiry || kind == MiscKind::LenParamInquiry) { // Convert x%KIND -> intrinsic KIND(x), x%LEN -> intrinsic LEN(x) - return MakeFunctionRef( - name, ActualArguments{ActualArgument{std::move(*base)}}); + ActualArgument arg{std::move(*base)}; + SetArgSourceLocation(arg, name); + return MakeFunctionRef(name, ActualArguments{std::move(arg)}); } else { DIE("unexpected MiscDetails::Kind"); } @@ -3156,6 +3176,7 @@ if (MaybeExpr expr{context_.Analyze(x)}) { if (!IsConstantExpr(*expr)) { actuals_.emplace_back(std::move(*expr)); + SetArgSourceLocation(actuals_.back(), x.GetSource()); return; } const Symbol *symbol{GetLastSymbol(*expr)}; @@ -3187,6 +3208,7 @@ std::visit(common::visitors{ [&](const common::Indirection &x) { actual = AnalyzeExpr(x.value()); + SetArgSourceLocation(actual, x.value().source); }, [&](const parser::AltReturnSpec &label) { if (!isSubroutine) { @@ -3494,13 +3516,17 @@ if (const Symbol * assumedTypeDummy{AssumedTypeDummy(expr)}) { expr.typedExpr.Reset(new GenericExprWrapper{}, GenericExprWrapper::Deleter); if (isProcedureCall_) { - return ActualArgument{ActualArgument::AssumedType{*assumedTypeDummy}}; + ActualArgument arg{ActualArgument::AssumedType{*assumedTypeDummy}}; + SetArgSourceLocation(arg, expr.source); + return std::move(arg); } context_.SayAt(expr.source, "TYPE(*) dummy argument may only be used as an actual argument"_err_en_US); } else if (MaybeExpr argExpr{AnalyzeExprOrWholeAssumedSizeArray(expr)}) { if (isProcedureCall_ || !IsProcedure(*argExpr)) { - return ActualArgument{std::move(*argExpr)}; + ActualArgument arg{std::move(*argExpr)}; + SetArgSourceLocation(arg, expr.source); + return std::move(arg); } context_.SayAt(expr.source, IsFunction(*argExpr) ? "Function call must have argument list"_err_en_US @@ -3560,7 +3586,12 @@ lhsType.kind() == rhsType.kind()) { // no conversion necessary } else if (auto rhsExpr{evaluate::ConvertToType(lhsType, MoveExpr(1))}) { + std::optional source; + if (actuals_[1]) { + source = actuals_[1]->sourceLocation(); + } actuals_[1] = ActualArgument{*rhsExpr}; + SetArgSourceLocation(actuals_[1], source); } else { actuals_[1] = std::nullopt; }