@@ -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 &, bool isError);
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,129 @@ void CheckHelper::CheckProcedureAssemblyName(const Symbol &symbol) {
2758
2766
}
2759
2767
}
2760
2768
2769
+ parser::Messages CheckHelper::WhyNotInteroperableDerivedType (
2770
+ const Symbol &symbol, bool isError) {
2771
+ parser::Messages msgs;
2772
+ if (examinedByWhyNotInteroperableDerivedType_.find (symbol) !=
2773
+ examinedByWhyNotInteroperableDerivedType_.end ()) {
2774
+ return msgs;
2775
+ }
2776
+ isError |= symbol.attrs ().test (Attr::BIND_C);
2777
+ examinedByWhyNotInteroperableDerivedType_.insert (symbol);
2778
+ if (const auto *derived{symbol.detailsIf <DerivedTypeDetails>()}) {
2779
+ if (derived->sequence ()) { // C1801
2780
+ msgs.Say (symbol.name (),
2781
+ " An interoperable derived type cannot have the SEQUENCE attribute" _err_en_US);
2782
+ } else if (!derived->paramDecls ().empty ()) { // C1802
2783
+ msgs.Say (symbol.name (),
2784
+ " An interoperable derived type cannot have a type parameter" _err_en_US);
2785
+ } else if (const auto *parent{
2786
+ symbol.scope ()->GetDerivedTypeParent ()}) { // C1803
2787
+ if (isError) {
2788
+ msgs.Say (symbol.name (),
2789
+ " A derived type with the BIND attribute cannot be an extended derived type" _err_en_US);
2790
+ } else {
2791
+ bool interoperableParent{true };
2792
+ if (parent->symbol ()) {
2793
+ auto bad{WhyNotInteroperableDerivedType (*parent->symbol (), false )};
2794
+ if (bad.AnyFatalError ()) {
2795
+ auto &msg{msgs.Say (symbol.name (),
2796
+ " The parent of an interoperable type is not interoperable" _err_en_US)};
2797
+ bad.AttachTo (msg, parser::Severity::None);
2798
+ interoperableParent = false ;
2799
+ }
2800
+ }
2801
+ if (interoperableParent) {
2802
+ msgs.Say (symbol.name (),
2803
+ " An interoperable type should not be an extended derived type" _warn_en_US);
2804
+ }
2805
+ }
2806
+ }
2807
+ const Symbol *parentComponent{symbol.scope ()
2808
+ ? derived->GetParentComponent (*symbol.scope ())
2809
+ : nullptr };
2810
+ for (const auto &pair : *symbol.scope ()) {
2811
+ const Symbol &component{*pair.second };
2812
+ if (&component == parentComponent) {
2813
+ continue ; // was checked above
2814
+ }
2815
+ if (IsProcedure (component)) { // C1804
2816
+ msgs.Say (component.name (),
2817
+ " An interoperable derived type cannot have a type bound procedure" _err_en_US);
2818
+ } else if (IsAllocatableOrPointer (component)) { // C1806
2819
+ msgs.Say (component.name (),
2820
+ " An interoperable derived type cannot have a pointer or allocatable component" _err_en_US);
2821
+ } else if (const auto *type{component.GetType ()}) {
2822
+ if (const auto *derived{type->AsDerived ()}) {
2823
+ auto bad{
2824
+ WhyNotInteroperableDerivedType (derived->typeSymbol (), isError)};
2825
+ if (bad.AnyFatalError ()) {
2826
+ auto &msg{msgs.Say (component.name (),
2827
+ " Component '%s' of an interoperable derived type must have an interoperable type but does not" _err_en_US,
2828
+ component.name ())};
2829
+ bad.AttachTo (msg, parser::Severity::None);
2830
+ } else if (!derived->typeSymbol ().GetUltimate ().attrs ().test (
2831
+ Attr::BIND_C)) {
2832
+ auto &msg{
2833
+ msgs.Say (component.name (),
2834
+ " Derived type of component '%s' of an interoperable derived type should have the BIND attribute" _warn_en_US,
2835
+ component.name ())
2836
+ .Attach (derived->typeSymbol ().name (),
2837
+ " Non-BIND(C) component type" _en_US)};
2838
+ bad.AttachTo (msg, parser::Severity::None);
2839
+ } else {
2840
+ msgs.Annex (std::move (bad));
2841
+ }
2842
+ } else if (!IsInteroperableIntrinsicType (
2843
+ *type, context_.languageFeatures ())) {
2844
+ auto maybeDyType{evaluate::DynamicType::From (*type)};
2845
+ if (type->category () == DeclTypeSpec::Logical) {
2846
+ if (context_.ShouldWarn (common::UsageWarning::LogicalVsCBool)) {
2847
+ msgs.Say (component.name (),
2848
+ " A LOGICAL component of an interoperable type should have the interoperable KIND=C_BOOL" _port_en_US);
2849
+ }
2850
+ } else if (type->category () == DeclTypeSpec::Character &&
2851
+ maybeDyType && maybeDyType->kind () == 1 ) {
2852
+ if (context_.ShouldWarn (common::UsageWarning::BindCCharLength)) {
2853
+ msgs.Say (component.name (),
2854
+ " A CHARACTER component of an interoperable type should have length 1" _port_en_US);
2855
+ }
2856
+ } else {
2857
+ msgs.Say (component.name (),
2858
+ " Each component of an interoperable derived type must have an interoperable type" _err_en_US);
2859
+ }
2860
+ }
2861
+ }
2862
+ if (auto extents{
2863
+ evaluate::GetConstantExtents (foldingContext_, &component)};
2864
+ extents && evaluate::GetSize (*extents) == 0 ) {
2865
+ msgs.Say (component.name (),
2866
+ " An array component of an interoperable type must have at least one element" _err_en_US);
2867
+ }
2868
+ }
2869
+ if (derived->componentNames ().empty ()) { // F'2023 C1805
2870
+ if (context_.ShouldWarn (common::LanguageFeature::EmptyBindCDerivedType)) {
2871
+ msgs.Say (symbol.name (),
2872
+ " A derived type with the BIND attribute should not be empty" _port_en_US);
2873
+ }
2874
+ }
2875
+ }
2876
+ if (isError) {
2877
+ for (auto &m : msgs.messages ()) {
2878
+ if (!m.IsFatal ()) {
2879
+ m.set_severity (parser::Severity::Error);
2880
+ }
2881
+ }
2882
+ }
2883
+ return msgs;
2884
+ }
2885
+
2761
2886
void CheckHelper::CheckBindC (const Symbol &symbol) {
2762
2887
bool isExplicitBindC{symbol.attrs ().test (Attr::BIND_C)};
2763
2888
if (isExplicitBindC) {
2764
- CheckConflicting (symbol, Attr::BIND_C, Attr::PARAMETER);
2765
2889
CheckConflicting (symbol, Attr::BIND_C, Attr::ELEMENTAL);
2890
+ CheckConflicting (symbol, Attr::BIND_C, Attr::INTRINSIC);
2891
+ CheckConflicting (symbol, Attr::BIND_C, Attr::PARAMETER);
2766
2892
} else {
2767
2893
// symbol must be interoperable (e.g., dummy argument of interoperable
2768
2894
// procedure interface) but is not itself BIND(C).
@@ -2832,13 +2958,30 @@ void CheckHelper::CheckBindC(const Symbol &symbol) {
2832
2958
}
2833
2959
if (const auto *type{symbol.GetType ()}) {
2834
2960
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);
2961
+ if (derived) {
2962
+ if (derived->typeSymbol ().attrs ().test (Attr::BIND_C)) {
2963
+ } else if (isExplicitBindC) {
2964
+ if (auto *msg{messages_.Say (symbol.name (),
2965
+ " The derived type of a BIND(C) object must also be BIND(C)" _err_en_US)}) {
2966
+ msg->Attach (derived->typeSymbol ().name (), " Non-BIND(C) type" _en_US);
2967
+ }
2968
+ context_.SetError (symbol);
2969
+ } else if (auto bad{WhyNotInteroperableDerivedType (
2970
+ derived->typeSymbol (), false )};
2971
+ !bad.empty ()) {
2972
+ if (auto *msg{messages_.Say (symbol.name (),
2973
+ " The derived type of an interoperable object must be interoperable, but is not" _err_en_US)}) {
2974
+ msg->Attach (
2975
+ derived->typeSymbol ().name (), " Non-interoperable type" _en_US);
2976
+ bad.AttachTo (*msg, parser::Severity::None);
2977
+ }
2978
+ context_.SetError (symbol);
2979
+ } else {
2980
+ if (auto *msg{messages_.Say (symbol.name (),
2981
+ " The derived type of an interoperable object should be BIND(C)" _warn_en_US)}) {
2982
+ msg->Attach (derived->typeSymbol ().name (), " Non-BIND(C) type" _en_US);
2983
+ }
2840
2984
}
2841
- context_.SetError (symbol);
2842
2985
}
2843
2986
if (type->IsAssumedType () || IsAssumedLengthCharacter (symbol)) {
2844
2987
// ok
@@ -2881,17 +3024,20 @@ void CheckHelper::CheckBindC(const Symbol &symbol) {
2881
3024
" An interoperable pointer must not be CONTIGUOUS" _err_en_US);
2882
3025
}
2883
3026
} 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);
3027
+ if (!IsBindCProcedure (symbol) && proc->isDummy ()) {
3028
+ messages_.Say (symbol.name (),
3029
+ " A dummy procedure to an interoperable procedure must also be interoperable" _err_en_US);
3030
+ context_.SetError (symbol);
3031
+ } else if (!proc->procInterface ()) {
3032
+ if (context_.ShouldWarn (
3033
+ common::LanguageFeature::NonBindCInteroperability)) {
3034
+ WarnIfNotInModuleFile (symbol.name (),
3035
+ " An interface name with BIND attribute should be specified if the BIND attribute is specified in a procedure declaration statement" _warn_en_US);
2894
3036
}
3037
+ } else if (!proc->procInterface ()->attrs ().test (Attr::BIND_C)) {
3038
+ messages_.Say (symbol.name (),
3039
+ " An interface name with BIND attribute must be specified if the BIND attribute is specified in a procedure declaration statement" _err_en_US);
3040
+ context_.SetError (symbol);
2895
3041
}
2896
3042
} else if (const auto *subp{symbol.detailsIf <SubprogramDetails>()}) {
2897
3043
for (const Symbol *dummy : subp->dummyArgs ()) {
@@ -2903,77 +3049,18 @@ void CheckHelper::CheckBindC(const Symbol &symbol) {
2903
3049
context_.SetError (symbol);
2904
3050
}
2905
3051
}
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
- }
3052
+ } else if (symbol.has <DerivedTypeDetails>()) {
3053
+ if (auto msgs{WhyNotInteroperableDerivedType (symbol, false )};
3054
+ !msgs.empty ()) {
3055
+ bool anyFatal{msgs.AnyFatalError ()};
3056
+ if (msgs.AnyFatalError () ||
3057
+ (!InModuleFile () &&
3058
+ context_.ShouldWarn (
3059
+ common::LanguageFeature::NonBindCInteroperability))) {
3060
+ context_.messages ().Annex (std::move (msgs));
2971
3061
}
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);
3062
+ if (anyFatal) {
3063
+ context_.SetError (symbol);
2977
3064
}
2978
3065
}
2979
3066
}
0 commit comments