diff --git a/flang/include/flang/Evaluate/call.h b/flang/include/flang/Evaluate/call.h --- a/flang/include/flang/Evaluate/call.h +++ b/flang/include/flang/Evaluate/call.h @@ -16,6 +16,7 @@ #include "flang/Common/indirection.h" #include "flang/Common/reference.h" #include "flang/Parser/char-block.h" +#include "flang/Parser/parse-tree.h" #include "flang/Semantics/attr.h" #include #include @@ -73,6 +74,7 @@ explicit ActualArgument(Expr &&); explicit ActualArgument(common::CopyableIndirection> &&); explicit ActualArgument(AssumedType); + explicit ActualArgument(parser::Label); ~ActualArgument(); ActualArgument &operator=(Expr &&); @@ -108,8 +110,9 @@ std::optional keyword() const { return keyword_; } void set_keyword(parser::CharBlock x) { keyword_ = x; } - bool isAlternateReturn() const { return isAlternateReturn_; } - void set_isAlternateReturn() { isAlternateReturn_ = true; } + bool isAlternateReturn() const { + return std::holds_alternative(u_); + } bool isPassedObject() const { return isPassedObject_; } void set_isPassedObject(bool yes = true) { isPassedObject_ = yes; } @@ -131,9 +134,10 @@ // e.g. between X and (X). The parser attempts to parse each argument // first as a variable, then as an expression, and the distinction appears // in the parse tree. - std::variant>, AssumedType> u_; + std::variant>, AssumedType, + parser::Label> + u_; std::optional keyword_; - bool isAlternateReturn_{false}; // whether expr is a "*label" number bool isPassedObject_{false}; common::Intent dummyIntent_{common::Intent::Default}; }; diff --git a/flang/lib/Evaluate/call.cpp b/flang/lib/Evaluate/call.cpp --- a/flang/lib/Evaluate/call.cpp +++ b/flang/lib/Evaluate/call.cpp @@ -20,6 +20,7 @@ ActualArgument::ActualArgument(common::CopyableIndirection> &&v) : u_{std::move(v)} {} ActualArgument::ActualArgument(AssumedType x) : u_{x} {} +ActualArgument::ActualArgument(parser::Label x) : u_{x} {} ActualArgument::~ActualArgument() {} ActualArgument::AssumedType::AssumedType(const Symbol &symbol) @@ -54,9 +55,8 @@ } bool ActualArgument::operator==(const ActualArgument &that) const { - return keyword_ == that.keyword_ && - isAlternateReturn_ == that.isAlternateReturn_ && - isPassedObject_ == that.isPassedObject_ && u_ == that.u_; + return keyword_ == that.keyword_ && isPassedObject_ == that.isPassedObject_ && + u_ == that.u_; } void ActualArgument::Parenthesize() { diff --git a/flang/lib/Evaluate/formatting.cpp b/flang/lib/Evaluate/formatting.cpp --- a/flang/lib/Evaluate/formatting.cpp +++ b/flang/lib/Evaluate/formatting.cpp @@ -108,14 +108,16 @@ if (keyword_) { o << keyword_->ToString() << '='; } - if (isAlternateReturn_) { - o << '*'; - } - if (const auto *expr{UnwrapExpr()}) { - return expr->AsFortran(o); - } else { - return std::get(u_).AsFortran(o); - } + std::visit( + common::visitors{ + [&](const common::CopyableIndirection> &expr) { + expr.value().AsFortran(o); + }, + [&](const AssumedType &assumedType) { assumedType.AsFortran(o); }, + [&](const parser::Label &label) { o << '*' << label; }, + }, + u_); + return o; } llvm::raw_ostream &SpecificIntrinsic::AsFortran(llvm::raw_ostream &o) const { diff --git a/flang/lib/Semantics/check-call.cpp b/flang/lib/Semantics/check-call.cpp --- a/flang/lib/Semantics/check-call.cpp +++ b/flang/lib/Semantics/check-call.cpp @@ -647,7 +647,7 @@ CheckProcedureArg(arg, proc, dummyName, context); }, [&](const characteristics::AlternateReturn &) { - // TODO check alternate return + // All semantic checking is done elsewhere }, }, dummy.u); diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp --- a/flang/lib/Semantics/expression.cpp +++ b/flang/lib/Semantics/expression.cpp @@ -2858,12 +2858,13 @@ // proc-component-ref actual = AnalyzeExpr(x.value()); }, - [&](const parser::AltReturnSpec &) { + [&](const parser::AltReturnSpec &x) { if (!isSubroutine) { context_.Say( "alternate return specification may not appear on" " function reference"_err_en_US); } + actual = ActualArgument(x.v); isAltReturn = true; }, [&](const parser::ActualArg::PercentRef &) { diff --git a/flang/test/Semantics/altreturn06.f90 b/flang/test/Semantics/altreturn06.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/altreturn06.f90 @@ -0,0 +1,16 @@ +! RUN: %S/test_errors.sh %s %t %f18 +! Test alternat return argument passing for internal and external subprograms +! Both of the following are OK + call extSubprogram (*100) + call intSubprogram (*100) + call extSubprogram (*101) + call intSubprogram (*101) +100 PRINT *,'First alternate return' +!ERROR: Label '101' is not a branch target +!ERROR: Label '101' is not a branch target +101 FORMAT("abc") +contains + subroutine intSubprogram(*) + return(1) + end subroutine +end