[flang-commits] [flang] 31e6cd2 - [flang] Implement cross-set EQUIVALENCE impossibility checking

peter klausler via flang-commits flang-commits at lists.llvm.org
Wed Jul 1 14:10:43 PDT 2020


Author: peter klausler
Date: 2020-07-01T14:09:07-07:00
New Revision: 31e6cd28a5a8afeea4a7f89d54ccf87eaba9f76c

URL: https://github.com/llvm/llvm-project/commit/31e6cd28a5a8afeea4a7f89d54ccf87eaba9f76c
DIFF: https://github.com/llvm/llvm-project/commit/31e6cd28a5a8afeea4a7f89d54ccf87eaba9f76c.diff

LOG: [flang] Implement cross-set EQUIVALENCE impossibility checking

Implement cross-set EQUIVALENCE impossibility checking; fixes
an infinite loop on an erroneous test.  Also fix substring
reference offset calculations in EQUIVALENCE discovered to
be incorrect during testing.

Reviewed By: tskeith

Differential Revision: https://reviews.llvm.org/D82993

Added: 
    

Modified: 
    flang/include/flang/Semantics/scope.h
    flang/lib/Semantics/compute-offsets.cpp
    flang/lib/Semantics/resolve-names-utils.cpp
    flang/test/Semantics/equivalence01.f90

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Semantics/scope.h b/flang/include/flang/Semantics/scope.h
index 3913889ac27b..a85a24770ef8 100644
--- a/flang/include/flang/Semantics/scope.h
+++ b/flang/include/flang/Semantics/scope.h
@@ -38,9 +38,10 @@ class SemanticsContext;
 // the indices for an array element, and the lower bound for a substring.
 struct EquivalenceObject {
   EquivalenceObject(Symbol &symbol, std::vector<ConstantSubscript> subscripts,
-      std::optional<ConstantSubscript> substringStart)
-      : symbol{symbol}, subscripts{subscripts}, substringStart{substringStart} {
-  }
+      std::optional<ConstantSubscript> substringStart, parser::CharBlock source)
+      : symbol{symbol}, subscripts{subscripts},
+        substringStart{substringStart}, source{source} {}
+
   bool operator==(const EquivalenceObject &) const;
   bool operator<(const EquivalenceObject &) const;
   std::string AsFortran() const;
@@ -48,6 +49,7 @@ struct EquivalenceObject {
   Symbol &symbol;
   std::vector<ConstantSubscript> subscripts; // for array elem
   std::optional<ConstantSubscript> substringStart;
+  parser::CharBlock source;
 };
 using EquivalenceSet = std::vector<EquivalenceObject>;
 

diff  --git a/flang/lib/Semantics/compute-offsets.cpp b/flang/lib/Semantics/compute-offsets.cpp
index 1a03c6ee47f9..bcc4c0caf46a 100644
--- a/flang/lib/Semantics/compute-offsets.cpp
+++ b/flang/lib/Semantics/compute-offsets.cpp
@@ -8,6 +8,7 @@
 
 #include "compute-offsets.h"
 #include "../../runtime/descriptor.h"
+#include "flang/Evaluate/fold-designator.h"
 #include "flang/Evaluate/fold.h"
 #include "flang/Evaluate/shape.h"
 #include "flang/Evaluate/type.h"
@@ -39,19 +40,23 @@ class ComputeOffsetsHelper {
     std::size_t alignment{0};
   };
   struct SymbolAndOffset {
-    Symbol *symbol{nullptr};
-    std::size_t offset{0};
+    SymbolAndOffset(Symbol &s, std::size_t off, const EquivalenceObject &obj)
+        : symbol{&s}, offset{off}, object{&obj} {}
+    SymbolAndOffset(const SymbolAndOffset &) = default;
+    Symbol *symbol;
+    std::size_t offset;
+    const EquivalenceObject *object;
   };
 
   void Compute(Scope &);
   void DoScope(Scope &);
   void DoCommonBlock(Symbol &);
-  void DoEquivalenceSet(EquivalenceSet &);
-  std::size_t GetOffset(SymbolAndOffset &);
+  void DoEquivalenceSet(const EquivalenceSet &);
+  SymbolAndOffset Resolve(const SymbolAndOffset &);
   std::size_t ComputeOffset(const EquivalenceObject &);
   void DoSymbol(Symbol &);
   SizeAndAlignment GetSizeAndAlignment(const Symbol &);
-  SizeAndAlignment GetElementSize(const Symbol &, bool isSubstring = false);
+  SizeAndAlignment GetElementSize(const Symbol &);
   std::size_t CountElements(const Symbol &);
   static std::size_t Align(std::size_t, std::size_t);
   static SizeAndAlignment GetIntrinsicSizeAndAlignment(TypeCategory, int);
@@ -85,7 +90,7 @@ void ComputeOffsetsHelper::DoScope(Scope &scope) {
     DoCommonBlock(*pair.second);
   }
   // Build dependents_ from equivalences: symbol -> symbol+offset
-  for (EquivalenceSet &set : scope.equivalenceSets()) {
+  for (const EquivalenceSet &set : scope.equivalenceSets()) {
     DoEquivalenceSet(set);
   }
   offset_ = 0;
@@ -100,7 +105,8 @@ void ComputeOffsetsHelper::DoScope(Scope &scope) {
     if (symbol->size() == 0) {
       SizeAndAlignment s{GetSizeAndAlignment(*symbol)};
       symbol->set_size(s.size);
-      symbol->set_offset(GetOffset(dep));
+      SymbolAndOffset resolved{Resolve(dep)};
+      symbol->set_offset(dep.symbol->offset() + resolved.offset);
       offset_ = std::max(offset_, symbol->offset() + symbol->size());
     }
   }
@@ -108,12 +114,16 @@ void ComputeOffsetsHelper::DoScope(Scope &scope) {
   scope.set_alignment(alignment_);
 }
 
-std::size_t ComputeOffsetsHelper::GetOffset(SymbolAndOffset &dep) {
+auto ComputeOffsetsHelper::Resolve(const SymbolAndOffset &dep)
+    -> SymbolAndOffset {
   auto it{dependents_.find(*dep.symbol)};
   if (it == dependents_.end()) {
-    return dep.symbol->offset() + dep.offset;
+    return dep;
   } else {
-    return GetOffset(it->second) + dep.offset;
+    SymbolAndOffset result{Resolve(it->second)};
+    result.offset += dep.offset;
+    result.object = dep.object;
+    return result;
   }
 }
 
@@ -128,22 +138,51 @@ void ComputeOffsetsHelper::DoCommonBlock(Symbol &commonBlock) {
   details.set_alignment(alignment_);
 }
 
-void ComputeOffsetsHelper::DoEquivalenceSet(EquivalenceSet &set) {
+void ComputeOffsetsHelper::DoEquivalenceSet(const EquivalenceSet &set) {
   std::vector<SymbolAndOffset> symbolOffsets;
-  SymbolAndOffset max;
-  for (EquivalenceObject &object : set) {
+  std::optional<std::size_t> representative;
+  for (const EquivalenceObject &object : set) {
     std::size_t offset{ComputeOffset(object)};
-    symbolOffsets.push_back({&object.symbol, offset});
-    if (offset >= max.offset) {
-      max.offset = offset;
-      max.symbol = &object.symbol;
+    SymbolAndOffset resolved{
+        Resolve(SymbolAndOffset{object.symbol, offset, object})};
+    symbolOffsets.push_back(resolved);
+    if (!representative ||
+        resolved.offset >= symbolOffsets[*representative].offset) {
+      // The equivalenced object with the largest offset from its resolved
+      // symbol will be the representative of this set, since the offsets
+      // of the other objects will be positive relative to it.
+      representative = symbolOffsets.size() - 1;
     }
   }
-  CHECK(max.symbol);
-  for (auto &[symbol, offset] : symbolOffsets) {
-    if (symbol != max.symbol) {
-      dependents_.emplace(
-          *symbol, SymbolAndOffset{max.symbol, max.offset - offset});
+  CHECK(representative);
+  const SymbolAndOffset &base{symbolOffsets[*representative]};
+  for (const auto &[symbol, offset, object] : symbolOffsets) {
+    if (symbol == base.symbol) {
+      if (offset != base.offset) {
+        auto x{evaluate::OffsetToDesignator(
+            context_.foldingContext(), *symbol, base.offset, 1)};
+        auto y{evaluate::OffsetToDesignator(
+            context_.foldingContext(), *symbol, offset, 1)};
+        if (x && y) {
+          context_
+              .Say(base.object->source,
+                  "'%s' and '%s' cannot have the same first storage unit"_err_en_US,
+                  x->AsFortran(), y->AsFortran())
+              .Attach(object->source, "Incompatible reference to '%s'"_en_US,
+                  y->AsFortran());
+        } else { // error recovery
+          context_
+              .Say(base.object->source,
+                  "'%s' (offset %zd bytes and %zd bytes) cannot have the same first storage unit"_err_en_US,
+                  symbol->name(), base.offset, offset)
+              .Attach(object->source,
+                  "Incompatible reference to '%s' offset %zd bytes"_en_US,
+                  symbol->name(), offset);
+        }
+      }
+    } else {
+      dependents_.emplace(*symbol,
+          SymbolAndOffset{*base.symbol, base.offset - offset, *object});
     }
   }
 }
@@ -152,9 +191,6 @@ void ComputeOffsetsHelper::DoEquivalenceSet(EquivalenceSet &set) {
 std::size_t ComputeOffsetsHelper::ComputeOffset(
     const EquivalenceObject &object) {
   std::size_t offset{0};
-  if (object.substringStart) {
-    offset = *object.substringStart - 1;
-  }
   if (!object.subscripts.empty()) {
     const ArraySpec &shape{object.symbol.get<ObjectEntityDetails>().shape()};
     auto lbound{[&](std::size_t i) {
@@ -172,8 +208,17 @@ std::size_t ComputeOffsetsHelper::ComputeOffset(
       offset *= ubound(i) - lbound(i) + 1;
     }
   }
-  return offset *
-      GetElementSize(object.symbol, object.substringStart.has_value()).size;
+  auto result{offset * GetElementSize(object.symbol).size};
+  if (object.substringStart) {
+    int kind{context_.defaultKinds().GetDefaultKind(TypeCategory::Character)};
+    if (const DeclTypeSpec * type{object.symbol.GetType()}) {
+      if (const IntrinsicTypeSpec * intrinsic{type->AsIntrinsic()}) {
+        kind = ToInt64(intrinsic->kind()).value_or(kind);
+      }
+    }
+    result += kind * (*object.substringStart - 1);
+  }
+  return result;
 }
 
 void ComputeOffsetsHelper::DoSymbol(Symbol &symbol) {
@@ -203,8 +248,8 @@ auto ComputeOffsetsHelper::GetSizeAndAlignment(const Symbol &symbol)
   return result;
 }
 
-auto ComputeOffsetsHelper::GetElementSize(
-    const Symbol &symbol, bool isSubstring) -> SizeAndAlignment {
+auto ComputeOffsetsHelper::GetElementSize(const Symbol &symbol)
+    -> SizeAndAlignment {
   const DeclTypeSpec *type{symbol.GetType()};
   if (!type) {
     return {};
@@ -226,7 +271,7 @@ auto ComputeOffsetsHelper::GetElementSize(
     if (auto kind{ToInt64(intrinsic->kind())}) {
       result = GetIntrinsicSizeAndAlignment(intrinsic->category(), *kind);
     }
-    if (!isSubstring && type->category() == DeclTypeSpec::Character) {
+    if (type->category() == DeclTypeSpec::Character) {
       ParamValue length{type->characterTypeSpec().length()};
       CHECK(length.isExplicit()); // else should be descriptor
       if (MaybeIntExpr lengthExpr{length.GetExplicit()}) {

diff  --git a/flang/lib/Semantics/resolve-names-utils.cpp b/flang/lib/Semantics/resolve-names-utils.cpp
index 5564570e263c..d6f0302e9854 100644
--- a/flang/lib/Semantics/resolve-names-utils.cpp
+++ b/flang/lib/Semantics/resolve-names-utils.cpp
@@ -365,7 +365,8 @@ void EquivalenceSets::AddToSet(const parser::Designator &designator) {
       }
     }
     auto substringStart{currObject_.substringStart};
-    currSet_.emplace_back(symbol, subscripts, substringStart);
+    currSet_.emplace_back(
+        symbol, subscripts, substringStart, designator.source);
     PropagateSaveAttr(currSet_.back(), currSet_);
   }
   currObject_ = {};
@@ -446,16 +447,7 @@ void EquivalenceSets::MergeInto(const parser::CharBlock &source,
   EquivalenceSet &dst{sets_[dstIndex]};
   PropagateSaveAttr(dst, src);
   for (const auto &obj : src) {
-    if (const auto *obj2{Find(dst, obj.symbol)}) {
-      if (obj == *obj2) {
-        continue; // already there
-      }
-      context_.Say(source,
-          "'%s' and '%s' cannot have the same first storage unit"_err_en_US,
-          obj2->AsFortran(), obj.AsFortran());
-    } else {
-      dst.push_back(obj);
-    }
+    dst.push_back(obj);
     objectToSet_[obj] = dstIndex;
   }
   PropagateSaveAttr(src, dst);

diff  --git a/flang/test/Semantics/equivalence01.f90 b/flang/test/Semantics/equivalence01.f90
index de60e8c9b2a4..404be570d657 100644
--- a/flang/test/Semantics/equivalence01.f90
+++ b/flang/test/Semantics/equivalence01.f90
@@ -113,7 +113,7 @@ subroutine s9
   equivalence(d(1:n), i)
   character(4) :: a(10)
   equivalence(c, a(10)(1:2))
-  !ERROR: 'a(10)' and 'a(10)(2:)' cannot have the same first storage unit
+  !ERROR: 'a(10_8)(2_8:2_8)' and 'a(10_8)(1_8:1_8)' cannot have the same first storage unit
   equivalence(c, a(10)(2:3))
 end
 
@@ -165,13 +165,20 @@ module s13
 
 module s14
   real :: a(10), b, c, d
-  !ERROR: 'a(1)' and 'a(2)' cannot have the same first storage unit
+  !ERROR: 'a(2_8)' and 'a(1_8)' cannot have the same first storage unit
   equivalence(a(1), a(2))
   equivalence(b, a(3))
-  !ERROR: 'a(3)' and 'a(4)' cannot have the same first storage unit
+  !ERROR: 'a(4_8)' and 'a(3_8)' cannot have the same first storage unit
   equivalence(a(4), b)
   equivalence(c, a(5))
+  !ERROR: 'a(6_8)' and 'a(5_8)' cannot have the same first storage unit
   equivalence(a(6), d)
-  !ERROR: 'a(5)' and 'a(6)' cannot have the same first storage unit
   equivalence(c, d)
 end
+
+module s15
+  real :: a(2), b(2)
+  equivalence(a(2),b(1))
+  !ERROR: 'a(3_8)' and 'a(1_8)' cannot have the same first storage unit
+  equivalence(b(2),a(1))
+end module


        


More information about the flang-commits mailing list