Index: flang/include/flang/Runtime/magic-numbers.h =================================================================== --- flang/include/flang/Runtime/magic-numbers.h +++ flang/include/flang/Runtime/magic-numbers.h @@ -39,4 +39,12 @@ #define FORTRAN_RUNTIME_STAT_STOPPED_IMAGE 104 #define FORTRAN_RUNTIME_STAT_UNLOCKED 105 #define FORTRAN_RUNTIME_STAT_UNLOCKED_FAILED_IMAGE 106 + +#if 0 +Status codes for GET_COMMAND_ARGUMENT. The status for 'value too short' needs +to be -1, the others must be positive. +#endif +#define FORTRAN_RUNTIME_STAT_INVALID_ARG_NUMBER 107 +#define FORTRAN_RUNTIME_STAT_MISSING_ARG 108 +#define FORTRAN_RUNTIME_STAT_VALUE_TOO_SHORT -1 #endif Index: flang/runtime/command.cpp =================================================================== --- flang/runtime/command.cpp +++ flang/runtime/command.cpp @@ -8,6 +8,7 @@ #include "flang/Runtime/command.h" #include "environment.h" +#include "stat.h" #include "flang/Runtime/descriptor.h" #include @@ -60,21 +61,21 @@ if (IsValidCharDescriptor(value)) { FillWithSpaces(value); } - return 1; + return ToErrmsg(errmsg, StatInvalidArgumentNumber); } if (IsValidCharDescriptor(value)) { LengthType argLen{ArgumentLength(n)}; if (argLen <= 0) { FillWithSpaces(value); - return 2; + return ToErrmsg(errmsg, StatMissingArgument); } if (argLen >= static_cast(value->ElementBytes())) { - return -1; + return ToErrmsg(errmsg, StatValueTooShort); } std::strncpy( value->OffsetElement(), executionEnvironment.argv[n], argLen + 1); } - return 0; + return StatOk; } } // namespace Fortran::runtime Index: flang/runtime/stat.h =================================================================== --- flang/runtime/stat.h +++ flang/runtime/stat.h @@ -44,6 +44,9 @@ StatUnlockedFailedImage = FORTRAN_RUNTIME_STAT_UNLOCKED_FAILED_IMAGE, // Additional "processor-defined" STAT= values + StatInvalidArgumentNumber = FORTRAN_RUNTIME_STAT_INVALID_ARG_NUMBER, + StatMissingArgument = FORTRAN_RUNTIME_STAT_MISSING_ARG, + StatValueTooShort = FORTRAN_RUNTIME_STAT_VALUE_TOO_SHORT, }; const char *StatErrorString(int); Index: flang/runtime/stat.cpp =================================================================== --- flang/runtime/stat.cpp +++ flang/runtime/stat.cpp @@ -50,6 +50,13 @@ case StatUnlockedFailedImage: return "Failed image unlocked"; + case StatInvalidArgumentNumber: + return "Invalid argument number"; + case StatMissingArgument: + return "Missing argument"; + case StatValueTooShort: + return "Value too short"; + default: return nullptr; } Index: flang/unittests/Runtime/CommandTest.cpp =================================================================== --- flang/unittests/Runtime/CommandTest.cpp +++ flang/unittests/Runtime/CommandTest.cpp @@ -7,13 +7,15 @@ //===----------------------------------------------------------------------===// #include "flang/Runtime/command.h" +#include "gmock/gmock.h" #include "gtest/gtest.h" #include "flang/Runtime/descriptor.h" #include "flang/Runtime/main.h" using namespace Fortran::runtime; +using ::testing::StartsWith; -template +template static OwningPtr CreateEmptyCharDescriptor() { OwningPtr descriptor{Descriptor::Create( sizeof(char), n, nullptr, 0, nullptr, CFI_attribute_allocatable)}; @@ -37,14 +39,20 @@ EXPECT_STREQ(value->OffsetElement(), argv); } - void CheckMissingArgumentValue(int n) const { + void CheckMissingArgumentValue(int n, const char *errStr = nullptr) const { OwningPtr value{CreateEmptyCharDescriptor()}; ASSERT_NE(value, nullptr); - EXPECT_GT(RTNAME(ArgumentValue)(n, value.get(), nullptr), 0); + OwningPtr err{errStr ? CreateEmptyCharDescriptor() : nullptr}; + + EXPECT_GT(RTNAME(ArgumentValue)(n, value.get(), err.get()), 0); std::string spaces(value->ElementBytes(), ' '); EXPECT_STREQ(value->OffsetElement(), spaces.c_str()); + + if (errStr) { + EXPECT_THAT(err->OffsetElement(), StartsWith(errStr)); + } } }; @@ -112,7 +120,6 @@ TEST_F(SeveralArguments, ArgumentValue) { CheckArgumentValue(0, severalArgsArgv[0]); CheckArgumentValue(1, severalArgsArgv[1]); - CheckMissingArgumentValue(2); CheckArgumentValue(3, severalArgsArgv[3]); CheckArgumentValue(4, severalArgsArgv[4]); } @@ -124,11 +131,26 @@ EXPECT_GT(RTNAME(ArgumentValue)(-1, nullptr, nullptr), 0); } -TEST_F(SeveralArguments, ArgumentValueErrors) { - CheckMissingArgumentValue(-1); +TEST_F(SeveralArguments, MissingArguments) { + CheckMissingArgumentValue(-1, "Invalid argument number"); + CheckMissingArgumentValue(2, "Missing argument"); + CheckMissingArgumentValue(5, "Invalid argument number"); CheckMissingArgumentValue(5); +} +TEST_F(SeveralArguments, ValueTooShort) { OwningPtr tooShort{CreateEmptyCharDescriptor<16>()}; ASSERT_NE(tooShort, nullptr); EXPECT_EQ(RTNAME(ArgumentValue)(1, tooShort.get(), nullptr), -1); + + OwningPtr errMsg{CreateEmptyCharDescriptor()}; + ASSERT_NE(errMsg, nullptr); + EXPECT_EQ(RTNAME(ArgumentValue)(1, tooShort.get(), errMsg.get()), -1); + EXPECT_THAT(errMsg->OffsetElement(), StartsWith("Value too short")); +} + +TEST_F(SeveralArguments, ErrMsgTooShort) { + OwningPtr errMsg{CreateEmptyCharDescriptor<3>()}; + EXPECT_GT(RTNAME(ArgumentValue)(-1, nullptr, errMsg.get()), 0); + EXPECT_STREQ(errMsg->OffsetElement(), "Inv"); }