[flang] Fix bug recognizing derived type constructor call
authorTim Keith <tkeith@nvidia.com>
Mon, 9 Jul 2018 22:25:49 +0000 (15:25 -0700)
committerTim Keith <tkeith@nvidia.com>
Mon, 9 Jul 2018 22:25:49 +0000 (15:25 -0700)
A ProcedureDesignator is a derived type constructor call if the name
resolves to a derived type. We need to recognize it as such and not
report an error. It may be in another derived type so we have to call
FindSymbol() first to find the derived type.

Most of the diffs are due to `symbol` changing from a reference to a
pointer.

In this example we were reporting an error on the first `t1()` and
resolving the second as an external function call.
```
module m
  type :: t1
  end type
  type(t1) :: x = t1()
  type t2
    type(t1) :: y = t1()
  end type
end module
```

Original-commit: flang-compiler/f18@717b22ca2b9e7ade24454b90b980f8c825fe4b12
Reviewed-on: https://github.com/flang-compiler/f18/pull/116

flang/lib/semantics/resolve-names.cc

index e522635..12634ac 100644 (file)
@@ -2147,45 +2147,50 @@ const Symbol *ResolveNamesVisitor::FindComponent(
 
 void ResolveNamesVisitor::Post(const parser::ProcedureDesignator &x) {
   if (const auto *name = std::get_if<parser::Name>(&x.u)) {
-    Symbol &symbol{MakeSymbol(name->source)};
-    if (symbol.has<UnknownDetails>()) {
-      if (isImplicitNoneExternal() && !symbol.attrs().test(Attr::EXTERNAL)) {
+    auto *symbol{FindSymbol(name->source)};
+    if (symbol == nullptr) {
+      symbol = &MakeSymbol(name->source);
+      if (isImplicitNoneExternal() && !symbol->attrs().test(Attr::EXTERNAL)) {
         Say(*name,
             "'%s' is an external procedure without the EXTERNAL"
             " attribute in a scope with IMPLICIT NONE(EXTERNAL)"_err_en_US);
       }
-      symbol.attrs().set(Attr::EXTERNAL);
-      symbol.set_details(ProcEntityDetails{});
-      if (const auto type = GetImplicitType(symbol)) {
-        symbol.details<ProcEntityDetails>().interface().set_type(*type);
+      symbol->attrs().set(Attr::EXTERNAL);
+      symbol->set_details(ProcEntityDetails{});
+      if (const auto type = GetImplicitType(*symbol)) {
+        symbol->details<ProcEntityDetails>().interface().set_type(*type);
       }
       CHECK(expectedProcFlag_);
-      symbol.set(*expectedProcFlag_);
-    } else if (CheckUseError(name->source, symbol)) {
+      symbol->set(*expectedProcFlag_);
+    } else if (symbol->has<UnknownDetails>()) {
+      CHECK(!"unexpected UnknownDetails");
+    } else if (CheckUseError(name->source, *symbol)) {
       // error was reported
     } else {
-      if (auto *details = symbol.detailsIf<EntityDetails>()) {
-        symbol.set_details(ProcEntityDetails(*details));
-        symbol.set(Symbol::Flag::Function);
+      if (auto *details = symbol->detailsIf<EntityDetails>()) {
+        symbol->set_details(ProcEntityDetails(*details));
+        symbol->set(Symbol::Flag::Function);
       }
-      if (symbol.test(Symbol::Flag::Function) &&
+      if (symbol->test(Symbol::Flag::Function) &&
           expectedProcFlag_ == Symbol::Flag::Subroutine) {
         Say2(name->source,
             "Cannot call function '%s' like a subroutine"_err_en_US,
-            symbol.name(), "Declaration of '%s'"_en_US);
-      } else if (symbol.test(Symbol::Flag::Subroutine) &&
+            symbol->name(), "Declaration of '%s'"_en_US);
+      } else if (symbol->test(Symbol::Flag::Subroutine) &&
           expectedProcFlag_ == Symbol::Flag::Function) {
         Say2(name->source,
             "Cannot call subroutine '%s' like a function"_err_en_US,
-            symbol.name(), "Declaration of '%s'"_en_US);
-      } else if (symbol.detailsIf<ProcEntityDetails>()) {
-        symbol.set(*expectedProcFlag_);  // in case it hasn't been set yet
-      } else if (symbol.detailsIf<GenericDetails>()) {
+            symbol->name(), "Declaration of '%s'"_en_US);
+      } else if (symbol->detailsIf<ProcEntityDetails>()) {
+        symbol->set(*expectedProcFlag_);  // in case it hasn't been set yet
+      } else if (symbol->detailsIf<GenericDetails>()) {
         // OK
+      } else if (symbol->detailsIf<DerivedTypeDetails>()) {
+        // OK: type constructor
       } else {
         Say2(name->source,
             "Use of '%s' as a procedure conflicts with its declaration"_err_en_US,
-            symbol.name(), "Declaration of '%s'"_en_US);
+            symbol->name(), "Declaration of '%s'"_en_US);
       }
     }
   }