@@ -417,24 +417,45 @@ std::optional<DummyDataObject> DummyDataObject::Characterize(
417417 return std::nullopt ;
418418}
419419
420- bool DummyDataObject::CanBePassedViaImplicitInterface () const {
420+ bool DummyDataObject::CanBePassedViaImplicitInterface (
421+ std::string *whyNot) const {
421422 if ((attrs &
422423 Attrs{Attr::Allocatable, Attr::Asynchronous, Attr::Optional,
423424 Attr::Pointer, Attr::Target, Attr::Value, Attr::Volatile})
424425 .any ()) {
426+ if (whyNot) {
427+ *whyNot = " a dummy argument has the allocatable, asynchronous, optional, "
428+ " pointer, target, value, or volatile attribute" ;
429+ }
425430 return false ; // 15.4.2.2(3)(a)
426431 } else if ((type.attrs () &
427432 TypeAndShape::Attrs{TypeAndShape::Attr::AssumedShape,
428433 TypeAndShape::Attr::AssumedRank,
429434 TypeAndShape::Attr::Coarray})
430435 .any ()) {
436+ if (whyNot) {
437+ *whyNot = " a dummy argument is assumed-shape, assumed-rank, or a coarray" ;
438+ }
431439 return false ; // 15.4.2.2(3)(b-d)
432440 } else if (type.type ().IsPolymorphic ()) {
441+ if (whyNot) {
442+ *whyNot = " a dummy argument is polymorphic" ;
443+ }
433444 return false ; // 15.4.2.2(3)(f)
434445 } else if (cudaDataAttr) {
446+ if (whyNot) {
447+ *whyNot = " a dummy argument has a CUDA data attribute" ;
448+ }
435449 return false ;
436450 } else if (const auto *derived{GetDerivedTypeSpec (type.type ())}) {
437- return derived->parameters ().empty (); // 15.4.2.2(3)(e)
451+ if (derived->parameters ().empty ()) { // 15.4.2.2(3)(e)
452+ return true ;
453+ } else {
454+ if (whyNot) {
455+ *whyNot = " a dummy argument has derived type parameters" ;
456+ }
457+ return false ;
458+ }
438459 } else {
439460 return true ;
440461 }
@@ -493,8 +514,12 @@ bool DummyProcedure::IsCompatibleWith(
493514 return true ;
494515}
495516
496- bool DummyProcedure::CanBePassedViaImplicitInterface () const {
517+ bool DummyProcedure::CanBePassedViaImplicitInterface (
518+ std::string *whyNot) const {
497519 if ((attrs & Attrs{Attr::Optional, Attr::Pointer}).any ()) {
520+ if (whyNot) {
521+ *whyNot = " a dummy procedure is optional or a pointer" ;
522+ }
498523 return false ; // 15.4.2.2(3)(a)
499524 }
500525 return true ;
@@ -895,11 +920,11 @@ common::Intent DummyArgument::GetIntent() const {
895920 u);
896921}
897922
898- bool DummyArgument::CanBePassedViaImplicitInterface () const {
923+ bool DummyArgument::CanBePassedViaImplicitInterface (std::string *whyNot ) const {
899924 if (const auto *object{std::get_if<DummyDataObject>(&u)}) {
900- return object->CanBePassedViaImplicitInterface ();
925+ return object->CanBePassedViaImplicitInterface (whyNot );
901926 } else if (const auto *proc{std::get_if<DummyProcedure>(&u)}) {
902- return proc->CanBePassedViaImplicitInterface ();
927+ return proc->CanBePassedViaImplicitInterface (whyNot );
903928 } else {
904929 return true ;
905930 }
@@ -970,13 +995,23 @@ bool FunctionResult::IsAssumedLengthCharacter() const {
970995 }
971996}
972997
973- bool FunctionResult::CanBeReturnedViaImplicitInterface () const {
998+ bool FunctionResult::CanBeReturnedViaImplicitInterface (
999+ std::string *whyNot) const {
9741000 if (attrs.test (Attr::Pointer) || attrs.test (Attr::Allocatable)) {
1001+ if (whyNot) {
1002+ *whyNot = " the function result is a pointer or allocatable" ;
1003+ }
9751004 return false ; // 15.4.2.2(4)(b)
9761005 } else if (cudaDataAttr) {
1006+ if (whyNot) {
1007+ *whyNot = " the function result has CUDA attributes" ;
1008+ }
9771009 return false ;
9781010 } else if (const auto *typeAndShape{GetTypeAndShape ()}) {
9791011 if (typeAndShape->Rank () > 0 ) {
1012+ if (whyNot) {
1013+ *whyNot = " the function result is an array" ;
1014+ }
9801015 return false ; // 15.4.2.2(4)(a)
9811016 } else {
9821017 const DynamicType &type{typeAndShape->type ()};
@@ -986,31 +1021,52 @@ bool FunctionResult::CanBeReturnedViaImplicitInterface() const {
9861021 return true ;
9871022 } else if (const auto *param{type.charLengthParamValue ()}) {
9881023 if (const auto &expr{param->GetExplicit ()}) {
989- return IsConstantExpr (*expr); // 15.4.2.2(4)(c)
1024+ if (IsConstantExpr (*expr)) { // 15.4.2.2(4)(c)
1025+ return true ;
1026+ } else {
1027+ if (whyNot) {
1028+ *whyNot = " the function result's length is not constant" ;
1029+ }
1030+ return false ;
1031+ }
9901032 } else if (param->isAssumed ()) {
9911033 return true ;
9921034 }
9931035 }
1036+ if (whyNot) {
1037+ *whyNot = " the function result's length is not known to the caller" ;
1038+ }
9941039 return false ;
9951040 case TypeCategory::Derived:
996- if (!type.IsPolymorphic ()) {
1041+ if (type.IsPolymorphic ()) {
1042+ if (whyNot) {
1043+ *whyNot = " the function result is polymorphic" ;
1044+ }
1045+ return false ;
1046+ } else {
9971047 const auto &spec{type.GetDerivedTypeSpec ()};
9981048 for (const auto &pair : spec.parameters ()) {
9991049 if (const auto &expr{pair.second .GetExplicit ()}) {
10001050 if (!IsConstantExpr (*expr)) {
1051+ if (whyNot) {
1052+ *whyNot = " the function result's derived type has a "
1053+ " non-constant parameter" ;
1054+ }
10011055 return false ; // 15.4.2.2(4)(c)
10021056 }
10031057 }
10041058 }
10051059 return true ;
10061060 }
1007- return false ;
10081061 default :
10091062 return true ;
10101063 }
10111064 }
10121065 } else {
1013- return false ; // 15.4.2.2(4)(b) - procedure pointer
1066+ if (whyNot) {
1067+ *whyNot = " the function result has unknown type or shape" ;
1068+ }
1069+ return false ; // 15.4.2.2(4)(b) - procedure pointer?
10141070 }
10151071}
10161072
@@ -1341,20 +1397,30 @@ std::optional<Procedure> Procedure::FromActuals(const ProcedureDesignator &proc,
13411397 return callee;
13421398}
13431399
1344- bool Procedure::CanBeCalledViaImplicitInterface () const {
1345- // TODO: Pass back information on why we return false
1346- if (attrs.test (Attr::Elemental) || attrs.test (Attr::BindC)) {
1400+ bool Procedure::CanBeCalledViaImplicitInterface (std::string *whyNot) const {
1401+ if (attrs.test (Attr::Elemental)) {
1402+ if (whyNot) {
1403+ *whyNot = " the procedure is elemental" ;
1404+ }
1405+ return false ; // 15.4.2.2(5,6)
1406+ } else if (attrs.test (Attr::BindC)) {
1407+ if (whyNot) {
1408+ *whyNot = " the procedure is BIND(C)" ;
1409+ }
13471410 return false ; // 15.4.2.2(5,6)
13481411 } else if (cudaSubprogramAttrs &&
13491412 *cudaSubprogramAttrs != common::CUDASubprogramAttrs::Host &&
13501413 *cudaSubprogramAttrs != common::CUDASubprogramAttrs::Global) {
1414+ if (whyNot) {
1415+ *whyNot = " the procedure is CUDA but neither HOST nor GLOBAL" ;
1416+ }
13511417 return false ;
13521418 } else if (IsFunction () &&
1353- !functionResult->CanBeReturnedViaImplicitInterface ()) {
1419+ !functionResult->CanBeReturnedViaImplicitInterface (whyNot )) {
13541420 return false ;
13551421 } else {
13561422 for (const DummyArgument &arg : dummyArguments) {
1357- if (!arg.CanBePassedViaImplicitInterface ()) {
1423+ if (!arg.CanBePassedViaImplicitInterface (whyNot )) {
13581424 return false ;
13591425 }
13601426 }
0 commit comments