@@ -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,8 @@ 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 (
141
+ const Symbol &, UnorderedSymbolSet &checked);
135
142
void CheckBindC (const Symbol &);
136
143
void CheckBindCFunctionResult (const Symbol &);
137
144
// Check functions for defined I/O procedures
@@ -2758,11 +2765,117 @@ void CheckHelper::CheckProcedureAssemblyName(const Symbol &symbol) {
2758
2765
}
2759
2766
}
2760
2767
2768
+ parser::Messages CheckHelper::WhyNotInteroperableDerivedType (
2769
+ const Symbol &symbol, UnorderedSymbolSet &checked) {
2770
+ parser::Messages msgs;
2771
+ if (checked.find (symbol) != checked.end ()) {
2772
+ return msgs;
2773
+ }
2774
+ checked.insert (symbol);
2775
+ if (const auto *derived{symbol.detailsIf <DerivedTypeDetails>()}) {
2776
+ if (derived->sequence ()) { // C1801
2777
+ msgs.Say (symbol.name (),
2778
+ " An interoperable derived type cannot have the SEQUENCE attribute" _err_en_US);
2779
+ } else if (!derived->paramDecls ().empty ()) { // C1802
2780
+ msgs.Say (symbol.name (),
2781
+ " An interoperable derived type cannot have a type parameter" _err_en_US);
2782
+ } else if (const auto *parent{
2783
+ symbol.scope ()->GetDerivedTypeParent ()}) { // C1803
2784
+ if (symbol.attrs ().test (Attr::BIND_C)) {
2785
+ msgs.Say (symbol.name (),
2786
+ " A derived type with the BIND attribute cannot be an extended derived type" _err_en_US);
2787
+ } else {
2788
+ bool interoperableParent{true };
2789
+ if (parent->symbol ()) {
2790
+ if (auto bad{
2791
+ WhyNotInteroperableDerivedType (*parent->symbol (), checked)};
2792
+ bad.AnyFatalError ()) {
2793
+ auto &msg{msgs.Say (symbol.name (),
2794
+ " The parent of an interoperable type is not interoperable" _err_en_US)};
2795
+ bad.AttachTo (msg, parser::Severity::None);
2796
+ interoperableParent = false ;
2797
+ }
2798
+ }
2799
+ if (interoperableParent) {
2800
+ msgs.Say (symbol.name (),
2801
+ " An interoperable type should not be an extended derived type" _warn_en_US);
2802
+ }
2803
+ }
2804
+ }
2805
+ const Symbol *parentComponent{symbol.scope ()
2806
+ ? derived->GetParentComponent (*symbol.scope ())
2807
+ : nullptr };
2808
+ for (const auto &pair : *symbol.scope ()) {
2809
+ const Symbol &component{*pair.second };
2810
+ if (&component == parentComponent) {
2811
+ continue ; // was checked above
2812
+ }
2813
+ if (IsProcedure (component)) { // C1804
2814
+ msgs.Say (component.name (),
2815
+ " An interoperable derived type cannot have a type bound procedure" _err_en_US);
2816
+ } else if (IsAllocatableOrPointer (component)) { // C1806
2817
+ msgs.Say (component.name (),
2818
+ " An interoperable derived type cannot have a pointer or allocatable component" _err_en_US);
2819
+ } else if (const auto *type{component.GetType ()}) {
2820
+ if (const auto *derived{type->AsDerived ()}) {
2821
+ if (auto bad{WhyNotInteroperableDerivedType (
2822
+ derived->typeSymbol (), checked)};
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,30 @@ 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
+ UnorderedSymbolSet checked;
2960
+ if (auto bad{WhyNotInteroperableDerivedType (
2961
+ derived->typeSymbol (), checked)};
2962
+ !bad.empty ()) {
2963
+ if (bad.AnyFatalError ()) {
2964
+ if (auto *msg{messages_.Say (symbol.name (),
2965
+ " The derived type of an interoperable object must be interoperable, but is not" _err_en_US)}) {
2966
+ bad.AttachTo (*msg, parser::Severity::None);
2967
+ }
2968
+ context_.SetError (symbol);
2969
+ }
2970
+ }
2840
2971
}
2841
- context_.SetError (symbol);
2842
2972
}
2843
2973
if (type->IsAssumedType () || IsAssumedLengthCharacter (symbol)) {
2844
2974
// ok
@@ -2881,17 +3011,20 @@ void CheckHelper::CheckBindC(const Symbol &symbol) {
2881
3011
" An interoperable pointer must not be CONTIGUOUS" _err_en_US);
2882
3012
}
2883
3013
} 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);
3014
+ if (!IsBindCProcedure (symbol) && proc->isDummy ()) {
3015
+ messages_.Say (symbol.name (),
3016
+ " A dummy procedure to an interoperable procedure must also be interoperable" _err_en_US);
3017
+ context_.SetError (symbol);
3018
+ } else if (!proc->procInterface ()) {
3019
+ if (context_.ShouldWarn (
3020
+ common::LanguageFeature::NonBindCInteroperability)) {
3021
+ WarnIfNotInModuleFile (symbol.name (),
3022
+ " An interface name with BIND attribute should be specified if the BIND attribute is specified in a procedure declaration statement" _warn_en_US);
2894
3023
}
3024
+ } else if (!proc->procInterface ()->attrs ().test (Attr::BIND_C)) {
3025
+ messages_.Say (symbol.name (),
3026
+ " An interface name with BIND attribute must be specified if the BIND attribute is specified in a procedure declaration statement" _err_en_US);
3027
+ context_.SetError (symbol);
2895
3028
}
2896
3029
} else if (const auto *subp{symbol.detailsIf <SubprogramDetails>()}) {
2897
3030
for (const Symbol *dummy : subp->dummyArgs ()) {
@@ -2903,77 +3036,18 @@ void CheckHelper::CheckBindC(const Symbol &symbol) {
2903
3036
context_.SetError (symbol);
2904
3037
}
2905
3038
}
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
- }
3039
+ } else if (symbol.has <DerivedTypeDetails>()) {
3040
+ UnorderedSymbolSet checked;
3041
+ if (auto msgs{WhyNotInteroperableDerivedType (symbol, checked)};
3042
+ !msgs.empty ()) {
3043
+ if (msgs.AnyFatalError ()) {
3044
+ context_.SetError (symbol);
2971
3045
}
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 );
3046
+ if (msgs. AnyFatalError () ||
3047
+ (! InModuleFile () &&
3048
+ context_.ShouldWarn (
3049
+ common::LanguageFeature::NonBindCInteroperability))) {
3050
+ context_. messages (). Annex ( std::move (msgs) );
2977
3051
}
2978
3052
}
2979
3053
}
0 commit comments