@@ -115,11 +115,16 @@ class CheckHelper {
115
115
}
116
116
return msg;
117
117
}
118
+ bool InModuleFile () const {
119
+ return FindModuleFileContaining (context_.FindScope (messages_.at ())) !=
120
+ nullptr ;
121
+ }
118
122
template <typename ... A> parser::Message *WarnIfNotInModuleFile (A &&...x) {
119
- if (FindModuleFileContaining (context_. FindScope (messages_. at ()) )) {
123
+ if (InModuleFile ( )) {
120
124
return nullptr ;
125
+ } else {
126
+ return messages_.Say (std::forward<A>(x)...);
121
127
}
122
- return messages_.Say (std::forward<A>(x)...);
123
128
}
124
129
template <typename ... A>
125
130
parser::Message *WarnIfNotInModuleFile (parser::CharBlock source, A &&...x) {
@@ -132,6 +137,7 @@ class CheckHelper {
132
137
void CheckGlobalName (const Symbol &);
133
138
void CheckProcedureAssemblyName (const Symbol &symbol);
134
139
void CheckExplicitSave (const Symbol &);
140
+ parser::Messages WhyNotInteroperableDerivedType (const Symbol &);
135
141
void CheckBindC (const Symbol &);
136
142
void CheckBindCFunctionResult (const Symbol &);
137
143
// Check functions for defined I/O procedures
@@ -182,6 +188,8 @@ class CheckHelper {
182
188
// Collection of target dependent assembly names of external and BIND(C)
183
189
// procedures.
184
190
std::map<std::string, SymbolRef> procedureAssemblyNames_;
191
+ // Derived types that have been examined by WhyNotInteroperableDerivedType
192
+ UnorderedSymbolSet examinedByWhyNotInteroperableDerivedType_;
185
193
};
186
194
187
195
class DistinguishabilityHelper {
@@ -2758,11 +2766,116 @@ void CheckHelper::CheckProcedureAssemblyName(const Symbol &symbol) {
2758
2766
}
2759
2767
}
2760
2768
2769
+ parser::Messages CheckHelper::WhyNotInteroperableDerivedType (
2770
+ const Symbol &symbol) {
2771
+ parser::Messages msgs;
2772
+ if (examinedByWhyNotInteroperableDerivedType_.find (symbol) !=
2773
+ examinedByWhyNotInteroperableDerivedType_.end ()) {
2774
+ return msgs;
2775
+ }
2776
+ examinedByWhyNotInteroperableDerivedType_.insert (symbol);
2777
+ if (const auto *derived{symbol.detailsIf <DerivedTypeDetails>()}) {
2778
+ if (derived->sequence ()) { // C1801
2779
+ msgs.Say (symbol.name (),
2780
+ " An interoperable derived type cannot have the SEQUENCE attribute" _err_en_US);
2781
+ } else if (!derived->paramDecls ().empty ()) { // C1802
2782
+ msgs.Say (symbol.name (),
2783
+ " An interoperable derived type cannot have a type parameter" _err_en_US);
2784
+ } else if (const auto *parent{
2785
+ symbol.scope ()->GetDerivedTypeParent ()}) { // C1803
2786
+ if (symbol.attrs ().test (Attr::BIND_C)) {
2787
+ msgs.Say (symbol.name (),
2788
+ " A derived type with the BIND attribute cannot be an extended derived type" _err_en_US);
2789
+ } else {
2790
+ bool interoperableParent{true };
2791
+ if (parent->symbol ()) {
2792
+ if (auto bad{WhyNotInteroperableDerivedType (*parent->symbol ())};
2793
+ bad.AnyFatalError ()) {
2794
+ auto &msg{msgs.Say (symbol.name (),
2795
+ " The parent of an interoperable type is not interoperable" _err_en_US)};
2796
+ bad.AttachTo (msg, parser::Severity::None);
2797
+ interoperableParent = false ;
2798
+ }
2799
+ }
2800
+ if (interoperableParent) {
2801
+ msgs.Say (symbol.name (),
2802
+ " An interoperable type should not be an extended derived type" _warn_en_US);
2803
+ }
2804
+ }
2805
+ }
2806
+ const Symbol *parentComponent{symbol.scope ()
2807
+ ? derived->GetParentComponent (*symbol.scope ())
2808
+ : nullptr };
2809
+ for (const auto &pair : *symbol.scope ()) {
2810
+ const Symbol &component{*pair.second };
2811
+ if (&component == parentComponent) {
2812
+ continue ; // was checked above
2813
+ }
2814
+ if (IsProcedure (component)) { // C1804
2815
+ msgs.Say (component.name (),
2816
+ " An interoperable derived type cannot have a type bound procedure" _err_en_US);
2817
+ } else if (IsAllocatableOrPointer (component)) { // C1806
2818
+ msgs.Say (component.name (),
2819
+ " An interoperable derived type cannot have a pointer or allocatable component" _err_en_US);
2820
+ } else if (const auto *type{component.GetType ()}) {
2821
+ if (const auto *derived{type->AsDerived ()}) {
2822
+ if (auto bad{WhyNotInteroperableDerivedType (derived->typeSymbol ())};
2823
+ bad.AnyFatalError ()) {
2824
+ auto &msg{msgs.Say (component.name (),
2825
+ " Component '%s' of an interoperable derived type must have an interoperable type but does not" _err_en_US,
2826
+ component.name ())};
2827
+ bad.AttachTo (msg, parser::Severity::None);
2828
+ } else if (!derived->typeSymbol ().GetUltimate ().attrs ().test (
2829
+ Attr::BIND_C)) {
2830
+ msgs.Say (component.name (),
2831
+ " Derived type of component '%s' of an interoperable derived type should have the BIND attribute" _warn_en_US,
2832
+ component.name ())
2833
+ .Attach (derived->typeSymbol ().name (),
2834
+ " Non-BIND(C) component type" _en_US);
2835
+ }
2836
+ } else if (!IsInteroperableIntrinsicType (
2837
+ *type, context_.languageFeatures ())) {
2838
+ auto maybeDyType{evaluate::DynamicType::From (*type)};
2839
+ if (type->category () == DeclTypeSpec::Logical) {
2840
+ if (context_.ShouldWarn (common::UsageWarning::LogicalVsCBool)) {
2841
+ msgs.Say (component.name (),
2842
+ " A LOGICAL component of an interoperable type should have the interoperable KIND=C_BOOL" _port_en_US);
2843
+ }
2844
+ } else if (type->category () == DeclTypeSpec::Character &&
2845
+ maybeDyType && maybeDyType->kind () == 1 ) {
2846
+ if (context_.ShouldWarn (common::UsageWarning::BindCCharLength)) {
2847
+ msgs.Say (component.name (),
2848
+ " A CHARACTER component of an interoperable type should have length 1" _port_en_US);
2849
+ }
2850
+ } else {
2851
+ msgs.Say (component.name (),
2852
+ " Each component of an interoperable derived type must have an interoperable type" _err_en_US);
2853
+ }
2854
+ }
2855
+ }
2856
+ if (auto extents{
2857
+ evaluate::GetConstantExtents (foldingContext_, &component)};
2858
+ extents && evaluate::GetSize (*extents) == 0 ) {
2859
+ msgs.Say (component.name (),
2860
+ " An array component of an interoperable type must have at least one element" _err_en_US);
2861
+ }
2862
+ }
2863
+ if (derived->componentNames ().empty ()) { // F'2023 C1805
2864
+ if (context_.ShouldWarn (common::LanguageFeature::EmptyBindCDerivedType)) {
2865
+ msgs.Say (symbol.name (),
2866
+ " A derived type with the BIND attribute should not be empty" _port_en_US);
2867
+ }
2868
+ }
2869
+ }
2870
+ return msgs;
2871
+ }
2872
+
2761
2873
void CheckHelper::CheckBindC (const Symbol &symbol) {
2762
2874
bool isExplicitBindC{symbol.attrs ().test (Attr::BIND_C)};
2763
2875
if (isExplicitBindC) {
2764
- CheckConflicting (symbol, Attr::BIND_C, Attr::PARAMETER);
2765
2876
CheckConflicting (symbol, Attr::BIND_C, Attr::ELEMENTAL);
2877
+ CheckConflicting (symbol, Attr::BIND_C, Attr::INTRINSIC);
2878
+ CheckConflicting (symbol, Attr::BIND_C, Attr::PARAMETER);
2766
2879
} else {
2767
2880
// symbol must be interoperable (e.g., dummy argument of interoperable
2768
2881
// procedure interface) but is not itself BIND(C).
@@ -2832,13 +2945,28 @@ void CheckHelper::CheckBindC(const Symbol &symbol) {
2832
2945
}
2833
2946
if (const auto *type{symbol.GetType ()}) {
2834
2947
const auto *derived{type->AsDerived ()};
2835
- if (derived && !derived->typeSymbol ().attrs ().test (Attr::BIND_C)) {
2836
- if (auto *msg{messages_.Say (symbol.name (),
2837
- " The derived type of a BIND(C) object must also be BIND(C)" _err_en_US)}) {
2838
- msg->Attach (
2839
- derived->typeSymbol ().name (), " Non-interoperable type" _en_US);
2948
+ if (derived) {
2949
+ if (isExplicitBindC) {
2950
+ if (!derived->typeSymbol ().attrs ().test (Attr::BIND_C)) {
2951
+ if (auto *msg{messages_.Say (symbol.name (),
2952
+ " The derived type of a BIND(C) object must also be BIND(C)" _err_en_US)}) {
2953
+ msg->Attach (
2954
+ derived->typeSymbol ().name (), " Non-interoperable type" _en_US);
2955
+ }
2956
+ context_.SetError (symbol);
2957
+ }
2958
+ } else {
2959
+ if (auto bad{WhyNotInteroperableDerivedType (derived->typeSymbol ())};
2960
+ !bad.empty ()) {
2961
+ if (bad.AnyFatalError ()) {
2962
+ if (auto *msg{messages_.Say (symbol.name (),
2963
+ " The derived type of an interoperable object must be interoperable, but is not" _err_en_US)}) {
2964
+ bad.AttachTo (*msg, parser::Severity::None);
2965
+ }
2966
+ context_.SetError (symbol);
2967
+ }
2968
+ }
2840
2969
}
2841
- context_.SetError (symbol);
2842
2970
}
2843
2971
if (type->IsAssumedType () || IsAssumedLengthCharacter (symbol)) {
2844
2972
// ok
@@ -2881,17 +3009,20 @@ void CheckHelper::CheckBindC(const Symbol &symbol) {
2881
3009
" An interoperable pointer must not be CONTIGUOUS" _err_en_US);
2882
3010
}
2883
3011
} else if (const auto *proc{symbol.detailsIf <ProcEntityDetails>()}) {
2884
- if (!proc->procInterface () ||
2885
- !proc->procInterface ()->attrs ().test (Attr::BIND_C)) {
2886
- if (proc->isDummy ()) {
2887
- messages_.Say (symbol.name (),
2888
- " A dummy procedure to an interoperable procedure must also be interoperable" _err_en_US);
2889
- context_.SetError (symbol);
2890
- } else {
2891
- messages_.Say (symbol.name (),
2892
- " An interface name with BIND attribute must be specified if the BIND attribute is specified in a procedure declaration statement" _err_en_US);
2893
- context_.SetError (symbol);
3012
+ if (!IsBindCProcedure (symbol) && proc->isDummy ()) {
3013
+ messages_.Say (symbol.name (),
3014
+ " A dummy procedure to an interoperable procedure must also be interoperable" _err_en_US);
3015
+ context_.SetError (symbol);
3016
+ } else if (!proc->procInterface ()) {
3017
+ if (context_.ShouldWarn (
3018
+ common::LanguageFeature::NonBindCInteroperability)) {
3019
+ WarnIfNotInModuleFile (symbol.name (),
3020
+ " An interface name with BIND attribute should be specified if the BIND attribute is specified in a procedure declaration statement" _warn_en_US);
2894
3021
}
3022
+ } else if (!proc->procInterface ()->attrs ().test (Attr::BIND_C)) {
3023
+ messages_.Say (symbol.name (),
3024
+ " An interface name with BIND attribute must be specified if the BIND attribute is specified in a procedure declaration statement" _err_en_US);
3025
+ context_.SetError (symbol);
2895
3026
}
2896
3027
} else if (const auto *subp{symbol.detailsIf <SubprogramDetails>()}) {
2897
3028
for (const Symbol *dummy : subp->dummyArgs ()) {
@@ -2903,77 +3034,16 @@ void CheckHelper::CheckBindC(const Symbol &symbol) {
2903
3034
context_.SetError (symbol);
2904
3035
}
2905
3036
}
2906
- } else if (const auto *derived{symbol.detailsIf <DerivedTypeDetails>()}) {
2907
- if (derived->sequence ()) { // C1801
2908
- messages_.Say (symbol.name (),
2909
- " A derived type with the BIND attribute cannot have the SEQUENCE attribute" _err_en_US);
2910
- context_.SetError (symbol);
2911
- } else if (!derived->paramDecls ().empty ()) { // C1802
2912
- messages_.Say (symbol.name (),
2913
- " A derived type with the BIND attribute has type parameter(s)" _err_en_US);
2914
- context_.SetError (symbol);
2915
- } else if (symbol.scope ()->GetDerivedTypeParent ()) { // C1803
2916
- messages_.Say (symbol.name (),
2917
- " A derived type with the BIND attribute cannot extend from another derived type" _err_en_US);
2918
- context_.SetError (symbol);
2919
- } else {
2920
- for (const auto &pair : *symbol.scope ()) {
2921
- const Symbol *component{&*pair.second };
2922
- if (IsProcedure (*component)) { // C1804
2923
- messages_.Say (component->name (),
2924
- " A derived type with the BIND attribute cannot have a type bound procedure" _err_en_US);
2925
- context_.SetError (symbol);
2926
- }
2927
- if (IsAllocatableOrPointer (*component)) { // C1806
2928
- messages_.Say (component->name (),
2929
- " A derived type with the BIND attribute cannot have a pointer or allocatable component" _err_en_US);
2930
- context_.SetError (symbol);
2931
- }
2932
- if (const auto *type{component->GetType ()}) {
2933
- if (const auto *derived{type->AsDerived ()}) {
2934
- if (!derived->typeSymbol ().attrs ().test (Attr::BIND_C)) {
2935
- if (auto *msg{messages_.Say (component->name (),
2936
- " Component '%s' of an interoperable derived type must have the BIND attribute" _err_en_US,
2937
- component->name ())}) {
2938
- msg->Attach (derived->typeSymbol ().name (),
2939
- " Non-interoperable component type" _en_US);
2940
- }
2941
- context_.SetError (symbol);
2942
- }
2943
- } else if (!IsInteroperableIntrinsicType (
2944
- *type, context_.languageFeatures ())) {
2945
- auto maybeDyType{evaluate::DynamicType::From (*type)};
2946
- if (type->category () == DeclTypeSpec::Logical) {
2947
- if (context_.ShouldWarn (common::UsageWarning::LogicalVsCBool)) {
2948
- WarnIfNotInModuleFile (component->name (),
2949
- " A LOGICAL component of a BIND(C) type should have the interoperable KIND=C_BOOL" _port_en_US);
2950
- }
2951
- } else if (type->category () == DeclTypeSpec::Character &&
2952
- maybeDyType && maybeDyType->kind () == 1 ) {
2953
- if (context_.ShouldWarn (common::UsageWarning::BindCCharLength)) {
2954
- WarnIfNotInModuleFile (component->name (),
2955
- " A CHARACTER component of a BIND(C) type should have length 1" _port_en_US);
2956
- }
2957
- } else {
2958
- messages_.Say (component->name (),
2959
- " Each component of an interoperable derived type must have an interoperable type" _err_en_US);
2960
- context_.SetError (symbol);
2961
- }
2962
- }
2963
- }
2964
- if (auto extents{
2965
- evaluate::GetConstantExtents (foldingContext_, component)};
2966
- extents && evaluate::GetSize (*extents) == 0 ) {
2967
- messages_.Say (component->name (),
2968
- " An array component of an interoperable type must have at least one element" _err_en_US);
2969
- context_.SetError (symbol);
2970
- }
3037
+ } else if (symbol.has <DerivedTypeDetails>()) {
3038
+ if (auto msgs{WhyNotInteroperableDerivedType (symbol)}; !msgs.empty ()) {
3039
+ if (msgs.AnyFatalError ()) {
3040
+ context_.SetError (symbol);
2971
3041
}
2972
- }
2973
- if (derived-> componentNames (). empty ()) { // F'2023 C1805
2974
- if ( context_.ShouldWarn (common::LanguageFeature::EmptyBindCDerivedType)) {
2975
- WarnIfNotInModuleFile (symbol. name (),
2976
- " A derived type with the BIND attribute is empty " _port_en_US );
3042
+ if (msgs. AnyFatalError () ||
3043
+ (! InModuleFile () &&
3044
+ context_.ShouldWarn (
3045
+ common::LanguageFeature::NonBindCInteroperability))) {
3046
+ context_. messages (). Annex ( std::move (msgs) );
2977
3047
}
2978
3048
}
2979
3049
}
0 commit comments