@@ -116,11 +116,16 @@ class CheckHelper {
116
116
}
117
117
return msg;
118
118
}
119
+ bool InModuleFile () const {
120
+ return FindModuleFileContaining (context_.FindScope (messages_.at ())) !=
121
+ nullptr ;
122
+ }
119
123
template <typename ... A> parser::Message *WarnIfNotInModuleFile (A &&...x) {
120
- if (FindModuleFileContaining (context_. FindScope (messages_. at ()) )) {
124
+ if (InModuleFile ( )) {
121
125
return nullptr ;
126
+ } else {
127
+ return messages_.Say (std::forward<A>(x)...);
122
128
}
123
- return messages_.Say (std::forward<A>(x)...);
124
129
}
125
130
template <typename ... A>
126
131
parser::Message *WarnIfNotInModuleFile (parser::CharBlock source, A &&...x) {
@@ -133,6 +138,7 @@ class CheckHelper {
133
138
void CheckGlobalName (const Symbol &);
134
139
void CheckProcedureAssemblyName (const Symbol &symbol);
135
140
void CheckExplicitSave (const Symbol &);
141
+ parser::Messages WhyNotInteroperableDerivedType (const Symbol &, bool isError);
136
142
void CheckBindC (const Symbol &);
137
143
void CheckBindCFunctionResult (const Symbol &);
138
144
// Check functions for defined I/O procedures
@@ -183,6 +189,8 @@ class CheckHelper {
183
189
// Collection of target dependent assembly names of external and BIND(C)
184
190
// procedures.
185
191
std::map<std::string, SymbolRef> procedureAssemblyNames_;
192
+ // Derived types that have been examined by WhyNotInteroperableDerivedType
193
+ UnorderedSymbolSet examinedByWhyNotInteroperableDerivedType_;
186
194
};
187
195
188
196
class DistinguishabilityHelper {
@@ -2822,11 +2830,129 @@ void CheckHelper::CheckProcedureAssemblyName(const Symbol &symbol) {
2822
2830
}
2823
2831
}
2824
2832
2833
+ parser::Messages CheckHelper::WhyNotInteroperableDerivedType (
2834
+ const Symbol &symbol, bool isError) {
2835
+ parser::Messages msgs;
2836
+ if (examinedByWhyNotInteroperableDerivedType_.find (symbol) !=
2837
+ examinedByWhyNotInteroperableDerivedType_.end ()) {
2838
+ return msgs;
2839
+ }
2840
+ isError |= symbol.attrs ().test (Attr::BIND_C);
2841
+ examinedByWhyNotInteroperableDerivedType_.insert (symbol);
2842
+ if (const auto *derived{symbol.detailsIf <DerivedTypeDetails>()}) {
2843
+ if (derived->sequence ()) { // C1801
2844
+ msgs.Say (symbol.name (),
2845
+ " An interoperable derived type cannot have the SEQUENCE attribute" _err_en_US);
2846
+ } else if (!derived->paramDecls ().empty ()) { // C1802
2847
+ msgs.Say (symbol.name (),
2848
+ " An interoperable derived type cannot have a type parameter" _err_en_US);
2849
+ } else if (const auto *parent{
2850
+ symbol.scope ()->GetDerivedTypeParent ()}) { // C1803
2851
+ if (isError) {
2852
+ msgs.Say (symbol.name (),
2853
+ " A derived type with the BIND attribute cannot be an extended derived type" _err_en_US);
2854
+ } else {
2855
+ bool interoperableParent{true };
2856
+ if (parent->symbol ()) {
2857
+ auto bad{WhyNotInteroperableDerivedType (*parent->symbol (), false )};
2858
+ if (bad.AnyFatalError ()) {
2859
+ auto &msg{msgs.Say (symbol.name (),
2860
+ " The parent of an interoperable type is not interoperable" _err_en_US)};
2861
+ bad.AttachTo (msg, parser::Severity::None);
2862
+ interoperableParent = false ;
2863
+ }
2864
+ }
2865
+ if (interoperableParent) {
2866
+ msgs.Say (symbol.name (),
2867
+ " An interoperable type should not be an extended derived type" _warn_en_US);
2868
+ }
2869
+ }
2870
+ }
2871
+ const Symbol *parentComponent{symbol.scope ()
2872
+ ? derived->GetParentComponent (*symbol.scope ())
2873
+ : nullptr };
2874
+ for (const auto &pair : *symbol.scope ()) {
2875
+ const Symbol &component{*pair.second };
2876
+ if (&component == parentComponent) {
2877
+ continue ; // was checked above
2878
+ }
2879
+ if (IsProcedure (component)) { // C1804
2880
+ msgs.Say (component.name (),
2881
+ " An interoperable derived type cannot have a type bound procedure" _err_en_US);
2882
+ } else if (IsAllocatableOrPointer (component)) { // C1806
2883
+ msgs.Say (component.name (),
2884
+ " An interoperable derived type cannot have a pointer or allocatable component" _err_en_US);
2885
+ } else if (const auto *type{component.GetType ()}) {
2886
+ if (const auto *derived{type->AsDerived ()}) {
2887
+ auto bad{
2888
+ WhyNotInteroperableDerivedType (derived->typeSymbol (), isError)};
2889
+ if (bad.AnyFatalError ()) {
2890
+ auto &msg{msgs.Say (component.name (),
2891
+ " Component '%s' of an interoperable derived type must have an interoperable type but does not" _err_en_US,
2892
+ component.name ())};
2893
+ bad.AttachTo (msg, parser::Severity::None);
2894
+ } else if (!derived->typeSymbol ().GetUltimate ().attrs ().test (
2895
+ Attr::BIND_C)) {
2896
+ auto &msg{
2897
+ msgs.Say (component.name (),
2898
+ " Derived type of component '%s' of an interoperable derived type should have the BIND attribute" _warn_en_US,
2899
+ component.name ())
2900
+ .Attach (derived->typeSymbol ().name (),
2901
+ " Non-BIND(C) component type" _en_US)};
2902
+ bad.AttachTo (msg, parser::Severity::None);
2903
+ } else {
2904
+ msgs.Annex (std::move (bad));
2905
+ }
2906
+ } else if (!IsInteroperableIntrinsicType (
2907
+ *type, context_.languageFeatures ())) {
2908
+ auto maybeDyType{evaluate::DynamicType::From (*type)};
2909
+ if (type->category () == DeclTypeSpec::Logical) {
2910
+ if (context_.ShouldWarn (common::UsageWarning::LogicalVsCBool)) {
2911
+ msgs.Say (component.name (),
2912
+ " A LOGICAL component of an interoperable type should have the interoperable KIND=C_BOOL" _port_en_US);
2913
+ }
2914
+ } else if (type->category () == DeclTypeSpec::Character &&
2915
+ maybeDyType && maybeDyType->kind () == 1 ) {
2916
+ if (context_.ShouldWarn (common::UsageWarning::BindCCharLength)) {
2917
+ msgs.Say (component.name (),
2918
+ " A CHARACTER component of an interoperable type should have length 1" _port_en_US);
2919
+ }
2920
+ } else {
2921
+ msgs.Say (component.name (),
2922
+ " Each component of an interoperable derived type must have an interoperable type" _err_en_US);
2923
+ }
2924
+ }
2925
+ }
2926
+ if (auto extents{
2927
+ evaluate::GetConstantExtents (foldingContext_, &component)};
2928
+ extents && evaluate::GetSize (*extents) == 0 ) {
2929
+ msgs.Say (component.name (),
2930
+ " An array component of an interoperable type must have at least one element" _err_en_US);
2931
+ }
2932
+ }
2933
+ if (derived->componentNames ().empty ()) { // F'2023 C1805
2934
+ if (context_.ShouldWarn (common::LanguageFeature::EmptyBindCDerivedType)) {
2935
+ msgs.Say (symbol.name (),
2936
+ " A derived type with the BIND attribute should not be empty" _port_en_US);
2937
+ }
2938
+ }
2939
+ }
2940
+ if (isError) {
2941
+ for (auto &m : msgs.messages ()) {
2942
+ if (!m.IsFatal ()) {
2943
+ m.set_severity (parser::Severity::Error);
2944
+ }
2945
+ }
2946
+ }
2947
+ return msgs;
2948
+ }
2949
+
2825
2950
void CheckHelper::CheckBindC (const Symbol &symbol) {
2826
2951
bool isExplicitBindC{symbol.attrs ().test (Attr::BIND_C)};
2827
2952
if (isExplicitBindC) {
2828
- CheckConflicting (symbol, Attr::BIND_C, Attr::PARAMETER);
2829
2953
CheckConflicting (symbol, Attr::BIND_C, Attr::ELEMENTAL);
2954
+ CheckConflicting (symbol, Attr::BIND_C, Attr::INTRINSIC);
2955
+ CheckConflicting (symbol, Attr::BIND_C, Attr::PARAMETER);
2830
2956
} else {
2831
2957
// symbol must be interoperable (e.g., dummy argument of interoperable
2832
2958
// procedure interface) but is not itself BIND(C).
@@ -2896,13 +3022,30 @@ void CheckHelper::CheckBindC(const Symbol &symbol) {
2896
3022
}
2897
3023
if (const auto *type{symbol.GetType ()}) {
2898
3024
const auto *derived{type->AsDerived ()};
2899
- if (derived && !derived->typeSymbol ().attrs ().test (Attr::BIND_C)) {
2900
- if (auto *msg{messages_.Say (symbol.name (),
2901
- " The derived type of a BIND(C) object must also be BIND(C)" _err_en_US)}) {
2902
- msg->Attach (
2903
- derived->typeSymbol ().name (), " Non-interoperable type" _en_US);
3025
+ if (derived) {
3026
+ if (derived->typeSymbol ().attrs ().test (Attr::BIND_C)) {
3027
+ } else if (isExplicitBindC) {
3028
+ if (auto *msg{messages_.Say (symbol.name (),
3029
+ " The derived type of a BIND(C) object must also be BIND(C)" _err_en_US)}) {
3030
+ msg->Attach (derived->typeSymbol ().name (), " Non-BIND(C) type" _en_US);
3031
+ }
3032
+ context_.SetError (symbol);
3033
+ } else if (auto bad{WhyNotInteroperableDerivedType (
3034
+ derived->typeSymbol (), false )};
3035
+ !bad.empty ()) {
3036
+ if (auto *msg{messages_.Say (symbol.name (),
3037
+ " The derived type of an interoperable object must be interoperable, but is not" _err_en_US)}) {
3038
+ msg->Attach (
3039
+ derived->typeSymbol ().name (), " Non-interoperable type" _en_US);
3040
+ bad.AttachTo (*msg, parser::Severity::None);
3041
+ }
3042
+ context_.SetError (symbol);
3043
+ } else {
3044
+ if (auto *msg{messages_.Say (symbol.name (),
3045
+ " The derived type of an interoperable object should be BIND(C)" _warn_en_US)}) {
3046
+ msg->Attach (derived->typeSymbol ().name (), " Non-BIND(C) type" _en_US);
3047
+ }
2904
3048
}
2905
- context_.SetError (symbol);
2906
3049
}
2907
3050
if (type->IsAssumedType () || IsAssumedLengthCharacter (symbol)) {
2908
3051
// ok
@@ -2945,17 +3088,20 @@ void CheckHelper::CheckBindC(const Symbol &symbol) {
2945
3088
" An interoperable pointer must not be CONTIGUOUS" _err_en_US);
2946
3089
}
2947
3090
} else if (const auto *proc{symbol.detailsIf <ProcEntityDetails>()}) {
2948
- if (!proc->procInterface () ||
2949
- !proc->procInterface ()->attrs ().test (Attr::BIND_C)) {
2950
- if (proc->isDummy ()) {
2951
- messages_.Say (symbol.name (),
2952
- " A dummy procedure to an interoperable procedure must also be interoperable" _err_en_US);
2953
- context_.SetError (symbol);
2954
- } else {
2955
- messages_.Say (symbol.name (),
2956
- " An interface name with BIND attribute must be specified if the BIND attribute is specified in a procedure declaration statement" _err_en_US);
2957
- context_.SetError (symbol);
3091
+ if (!IsBindCProcedure (symbol) && proc->isDummy ()) {
3092
+ messages_.Say (symbol.name (),
3093
+ " A dummy procedure to an interoperable procedure must also be interoperable" _err_en_US);
3094
+ context_.SetError (symbol);
3095
+ } else if (!proc->procInterface ()) {
3096
+ if (context_.ShouldWarn (
3097
+ common::LanguageFeature::NonBindCInteroperability)) {
3098
+ WarnIfNotInModuleFile (symbol.name (),
3099
+ " An interface name with BIND attribute should be specified if the BIND attribute is specified in a procedure declaration statement" _warn_en_US);
2958
3100
}
3101
+ } else if (!proc->procInterface ()->attrs ().test (Attr::BIND_C)) {
3102
+ messages_.Say (symbol.name (),
3103
+ " An interface name with BIND attribute must be specified if the BIND attribute is specified in a procedure declaration statement" _err_en_US);
3104
+ context_.SetError (symbol);
2959
3105
}
2960
3106
} else if (const auto *subp{symbol.detailsIf <SubprogramDetails>()}) {
2961
3107
for (const Symbol *dummy : subp->dummyArgs ()) {
@@ -2967,77 +3113,18 @@ void CheckHelper::CheckBindC(const Symbol &symbol) {
2967
3113
context_.SetError (symbol);
2968
3114
}
2969
3115
}
2970
- } else if (const auto *derived{symbol.detailsIf <DerivedTypeDetails>()}) {
2971
- if (derived->sequence ()) { // C1801
2972
- messages_.Say (symbol.name (),
2973
- " A derived type with the BIND attribute cannot have the SEQUENCE attribute" _err_en_US);
2974
- context_.SetError (symbol);
2975
- } else if (!derived->paramDecls ().empty ()) { // C1802
2976
- messages_.Say (symbol.name (),
2977
- " A derived type with the BIND attribute has type parameter(s)" _err_en_US);
2978
- context_.SetError (symbol);
2979
- } else if (symbol.scope ()->GetDerivedTypeParent ()) { // C1803
2980
- messages_.Say (symbol.name (),
2981
- " A derived type with the BIND attribute cannot extend from another derived type" _err_en_US);
2982
- context_.SetError (symbol);
2983
- } else {
2984
- for (const auto &pair : *symbol.scope ()) {
2985
- const Symbol *component{&*pair.second };
2986
- if (IsProcedure (*component)) { // C1804
2987
- messages_.Say (component->name (),
2988
- " A derived type with the BIND attribute cannot have a type bound procedure" _err_en_US);
2989
- context_.SetError (symbol);
2990
- }
2991
- if (IsAllocatableOrPointer (*component)) { // C1806
2992
- messages_.Say (component->name (),
2993
- " A derived type with the BIND attribute cannot have a pointer or allocatable component" _err_en_US);
2994
- context_.SetError (symbol);
2995
- }
2996
- if (const auto *type{component->GetType ()}) {
2997
- if (const auto *derived{type->AsDerived ()}) {
2998
- if (!derived->typeSymbol ().attrs ().test (Attr::BIND_C)) {
2999
- if (auto *msg{messages_.Say (component->name (),
3000
- " Component '%s' of an interoperable derived type must have the BIND attribute" _err_en_US,
3001
- component->name ())}) {
3002
- msg->Attach (derived->typeSymbol ().name (),
3003
- " Non-interoperable component type" _en_US);
3004
- }
3005
- context_.SetError (symbol);
3006
- }
3007
- } else if (!IsInteroperableIntrinsicType (
3008
- *type, context_.languageFeatures ())) {
3009
- auto maybeDyType{evaluate::DynamicType::From (*type)};
3010
- if (type->category () == DeclTypeSpec::Logical) {
3011
- if (context_.ShouldWarn (common::UsageWarning::LogicalVsCBool)) {
3012
- WarnIfNotInModuleFile (component->name (),
3013
- " A LOGICAL component of a BIND(C) type should have the interoperable KIND=C_BOOL" _port_en_US);
3014
- }
3015
- } else if (type->category () == DeclTypeSpec::Character &&
3016
- maybeDyType && maybeDyType->kind () == 1 ) {
3017
- if (context_.ShouldWarn (common::UsageWarning::BindCCharLength)) {
3018
- WarnIfNotInModuleFile (component->name (),
3019
- " A CHARACTER component of a BIND(C) type should have length 1" _port_en_US);
3020
- }
3021
- } else {
3022
- messages_.Say (component->name (),
3023
- " Each component of an interoperable derived type must have an interoperable type" _err_en_US);
3024
- context_.SetError (symbol);
3025
- }
3026
- }
3027
- }
3028
- if (auto extents{
3029
- evaluate::GetConstantExtents (foldingContext_, component)};
3030
- extents && evaluate::GetSize (*extents) == 0 ) {
3031
- messages_.Say (component->name (),
3032
- " An array component of an interoperable type must have at least one element" _err_en_US);
3033
- context_.SetError (symbol);
3034
- }
3116
+ } else if (symbol.has <DerivedTypeDetails>()) {
3117
+ if (auto msgs{WhyNotInteroperableDerivedType (symbol, false )};
3118
+ !msgs.empty ()) {
3119
+ bool anyFatal{msgs.AnyFatalError ()};
3120
+ if (msgs.AnyFatalError () ||
3121
+ (!InModuleFile () &&
3122
+ context_.ShouldWarn (
3123
+ common::LanguageFeature::NonBindCInteroperability))) {
3124
+ context_.messages ().Annex (std::move (msgs));
3035
3125
}
3036
- }
3037
- if (derived->componentNames ().empty ()) { // F'2023 C1805
3038
- if (context_.ShouldWarn (common::LanguageFeature::EmptyBindCDerivedType)) {
3039
- WarnIfNotInModuleFile (symbol.name (),
3040
- " A derived type with the BIND attribute is empty" _port_en_US);
3126
+ if (anyFatal) {
3127
+ context_.SetError (symbol);
3041
3128
}
3042
3129
}
3043
3130
}
0 commit comments