Skip to content

[flang] Further refine errors vs warnings for ambiguous generics #80161

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 20, 2024

Conversation

klausler
Copy link
Contributor

Ensure that the compiler emits a hard error for a generic interface with ambiguous specific procedures when it is declared as such, and the ambiguity doesn't involve optional or unlimited polymorphic dummy data arguments. But: emit an optional portability warning when the ambiguity in the generic interface is due to USE association's merging of multiple generics, as USE association may involve modules not under control of the programmer; we'll emit a hard error message if any the actual arguments in a particular reference to the generic procedure doesn't resolve to exactly one specific procedure. And don't emit warnings when potential ambiguity due to USE association is taking place in a module file; the warnings, if any, will have been produced when the module file was compiled.

@klausler klausler requested a review from jeanPerier January 31, 2024 16:39
@llvmbot llvmbot added flang Flang issues not falling into any other category flang:semantics labels Jan 31, 2024
@llvmbot
Copy link
Member

llvmbot commented Jan 31, 2024

@llvm/pr-subscribers-flang-semantics

Author: Peter Klausler (klausler)

Changes

Ensure that the compiler emits a hard error for a generic interface with ambiguous specific procedures when it is declared as such, and the ambiguity doesn't involve optional or unlimited polymorphic dummy data arguments. But: emit an optional portability warning when the ambiguity in the generic interface is due to USE association's merging of multiple generics, as USE association may involve modules not under control of the programmer; we'll emit a hard error message if any the actual arguments in a particular reference to the generic procedure doesn't resolve to exactly one specific procedure. And don't emit warnings when potential ambiguity due to USE association is taking place in a module file; the warnings, if any, will have been produced when the module file was compiled.


Full diff: https://github.com/llvm/llvm-project/pull/80161.diff

2 Files Affected:

  • (modified) flang/lib/Semantics/check-declarations.cpp (+28-15)
  • (modified) flang/test/Semantics/resolve17.f90 (+1-1)
diff --git a/flang/lib/Semantics/check-declarations.cpp b/flang/lib/Semantics/check-declarations.cpp
index 8af9dc11f822e..f701444e9ccd1 100644
--- a/flang/lib/Semantics/check-declarations.cpp
+++ b/flang/lib/Semantics/check-declarations.cpp
@@ -192,7 +192,7 @@ class DistinguishabilityHelper {
 
 private:
   void SayNotDistinguishable(const Scope &, const SourceName &, GenericKind,
-      const Symbol &, const Symbol &, bool isError);
+      const Symbol &, const Symbol &, bool isHardConflict);
   void AttachDeclaration(parser::Message &, const Scope &, const Symbol &);
 
   SemanticsContext &context_;
@@ -3512,6 +3512,13 @@ void DistinguishabilityHelper::Add(const Symbol &generic, GenericKind kind,
 }
 
 void DistinguishabilityHelper::Check(const Scope &scope) {
+#if 0
+  if (FindModuleFileContaining(scope)) {
+    // Distinguishability was checked when the module was created;
+    // don't let optional warnings then become errors now.
+    return;
+  }
+#endif
   for (const auto &[name, info] : nameToSpecifics_) {
     for (auto iter1{info.begin()}; iter1 != info.end(); ++iter1) {
       const auto &[ultimate, procInfo]{*iter1};
@@ -3533,15 +3540,19 @@ void DistinguishabilityHelper::Check(const Scope &scope) {
 
 void DistinguishabilityHelper::SayNotDistinguishable(const Scope &scope,
     const SourceName &name, GenericKind kind, const Symbol &proc1,
-    const Symbol &proc2, bool isError) {
-  if (!isError &&
-      !context_.ShouldWarn(
-          common::LanguageFeature::IndistinguishableSpecifics)) {
-    // The rules for distinguishing specific procedures (F'2023 15.4.3.4.5)
-    // are inadequate for some real-world cases like pFUnit.
-    // When there are optional dummy arguments or unlimited polymorphic
-    // dummy data object arguments, the best that we can do is emit an optional
-    // portability warning.
+    const Symbol &proc2, bool isHardConflict) {
+  bool isUseAssociated{!scope.sourceRange().Contains(name)};
+  // The rules for distinguishing specific procedures (F'2023 15.4.3.4.5)
+  // are inadequate for some real-world cases like pFUnit.
+  // When there are optional dummy arguments or unlimited polymorphic
+  // dummy data object arguments, the best that we can do is emit an optional
+  // portability warning.  Also, generics created by USE association
+  // merging shouldn't receive hard errors for ambiguity.
+  bool isWarning{!isHardConflict || isUseAssociated};
+  if (isWarning &&
+      (!context_.ShouldWarn(
+           common::LanguageFeature::IndistinguishableSpecifics) ||
+          FindModuleFileContaining(scope))) {
     return;
   }
   std::string name1{proc1.name().ToString()};
@@ -3556,17 +3567,19 @@ void DistinguishabilityHelper::SayNotDistinguishable(const Scope &scope,
     }
   }
   parser::Message *msg;
-  if (scope.sourceRange().Contains(name)) {
+  if (!isUseAssociated) {
+    CHECK(isWarning == !isHardConflict);
     msg = &context_.Say(name,
-        isError
+        isHardConflict
             ? "Generic '%s' may not have specific procedures '%s' and '%s' as their interfaces are not distinguishable"_err_en_US
             : "Generic '%s' should not have specific procedures '%s' and '%s' as their interfaces are not distinguishable by the rules in the standard"_port_en_US,
         MakeOpName(name), name1, name2);
   } else {
+    CHECK(isWarning);
     msg = &context_.Say(*GetTopLevelUnitContaining(proc1).GetName(),
-        isError
-            ? "USE-associated generic '%s' may not have specific procedures '%s' and '%s' as their interfaces are not distinguishable"_err_en_US
-            : "USE-associated generic '%s' should not have specific procedures '%s' and '%s' as their interfaces are not distinguishable by the incomplete rules in the standard"_port_en_US,
+        isHardConflict
+            ? "USE-associated generic '%s' should not have specific procedures '%s' and '%s' as their interfaces are not distinguishable"_warn_en_US
+            : "USE-associated generic '%s' should not have specific procedures '%s' and '%s' as their interfaces are not distinguishable by the rules in the standard"_port_en_US,
         MakeOpName(name), name1, name2);
   }
   AttachDeclaration(*msg, scope, proc1);
diff --git a/flang/test/Semantics/resolve17.f90 b/flang/test/Semantics/resolve17.f90
index 513676fe670a1..770af756d03bc 100644
--- a/flang/test/Semantics/resolve17.f90
+++ b/flang/test/Semantics/resolve17.f90
@@ -180,7 +180,7 @@ subroutine g()
   end
 end module
 subroutine s9
-  !ERROR: USE-associated generic 'g' may not have specific procedures 'g' and 'g' as their interfaces are not distinguishable
+  !PORTABILITY: USE-associated generic 'g' should not have specific procedures 'g' and 'g' as their interfaces are not distinguishable
   use m9a
   use m9b
 end

@klausler klausler force-pushed the pfunit4 branch 2 times, most recently from c541d10 to 87b94ad Compare January 31, 2024 20:21
Copy link
Contributor

@jeanPerier jeanPerier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes looks good to me, but one thing is not clear to me: what happens when a call to a generic is later resolved and falls in these ambiguous cases? It will be an error at that point, right?

@klausler
Copy link
Contributor Author

klausler commented Feb 1, 2024

The changes looks good to me, but one thing is not clear to me: what happens when a call to a generic is later resolved and falls in these ambiguous cases? It will be an error at that point, right?

Yes, certainly. This patch is for the ambiguity checker that looks at declarations. For declarations in modules, this checking might help the programmer of a module guarantee that their clients will never get the per-reference ambiguity error; but a module that gets warnings about ambiguities might have clients that get errors.

@jeanPerier
Copy link
Contributor

Yes, certainly. This patch is for the ambiguity checker that looks at declarations. For declarations in modules, this checking might help the programmer of a module guarantee that their clients will never get the per-reference ambiguity error; but a module that gets warnings about ambiguities might have clients that get errors.

Thanks for the explanation!

Ensure that the compiler emits a hard error for a generic interface
with ambiguous specific procedures when it is declared as such, and
the ambiguity doesn't involve optional or unlimited polymorphic dummy
data arguments.  But: emit an optional portability warning when the
ambiguity in the generic interface is due to USE association's merging
of multiple generics, as USE association may involve modules not under
control of the programmer; we'll emit a hard error message if any
the actual arguments in a particular reference to the generic procedure
doesn't resolve to exactly one specific procedure.  And don't emit
warnings when potential ambiguity due to USE association is taking
place in a module file; the warnings, if any, will have been produced
when the module file was compiled.
@klausler klausler merged commit 2236048 into llvm:main Feb 20, 2024
@klausler klausler deleted the pfunit4 branch February 20, 2024 22:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
flang:semantics flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants