[flang-commits] [flang] 3705e63 - [flang] Fix incorrect offset for zero-size COMMON block members. (#214174)
via flang-commits
flang-commits at lists.llvm.org
Thu Aug 6 09:20:59 PDT 2026
Author: Daniel Chen
Date: 2026-08-06T12:20:55-04:00
New Revision: 3705e63f8099e46c5a29ffef91a1cde9a91de392
URL: https://github.com/llvm/llvm-project/commit/3705e63f8099e46c5a29ffef91a1cde9a91de392
DIFF: https://github.com/llvm/llvm-project/commit/3705e63f8099e46c5a29ffef91a1cde9a91de392.diff
LOG: [flang] Fix incorrect offset for zero-size COMMON block members. (#214174)
Fixes #214171
`ComputeOffsetsHelper::DoSymbol()` in
`flang/lib/Semantics/compute-offsets.cpp` returned early without calling
`symbol.set_offset()` when a symbol had zero size (e.g. CHARACTER*0). As
a result, every zero-size symbol in a COMMON block retained its default
offset of 0 — the block base address — instead of its correct sequential
position.
This incorrect offset caused two observable bugs:
1. **Wrong storage address**: LOC() and lowering always returned the
block base address for zero-size members instead of their actual
sequential position.
2. **False "cannot backward-extend" error**: When a zero-size COMMON
block member appeared in an EQUIVALENCE association, the backward-extend
check (`dep.offset > symbol.offset()`) incorrectly fired because
`symbol.offset()` was always 0. For example, the following valid code
was falsely rejected:
```fortran
program p09
integer(8) :: i8
character(0) :: zc0
character(8) :: c8
common /blk/ i8, zc0
equivalence (c8(5:8), zc0)
end program
Error before fix:
`error: 'zc0' cannot backward-extend COMMON block /blk/ via EQUIVALENCE
with 'c8'`
After the fix, `zc0` is correctly assigned offset 8 (after `i8`), so
`dep.offset` (4) < `symbol.offset()` (8) and no error is raised.
Added:
flang/test/Lower/common-block-char0.f90
flang/test/Semantics/common-block-char0.f90
Modified:
flang/lib/Semantics/compute-offsets.cpp
Removed:
################################################################################
diff --git a/flang/lib/Semantics/compute-offsets.cpp b/flang/lib/Semantics/compute-offsets.cpp
index e427586301dea..3a355f040b865 100644
--- a/flang/lib/Semantics/compute-offsets.cpp
+++ b/flang/lib/Semantics/compute-offsets.cpp
@@ -397,6 +397,12 @@ std::size_t ComputeOffsetsHelper::DoSymbol(
}
SizeAndAlignment s{GetSizeAndAlignment(symbol, true)};
if (s.size == 0) {
+ // Zero-size symbols (e.g. CHARACTER*0) still occupy their sequential
+ // position in a COMMON block or derived-type sequence. Record the current
+ // offset so that LOC() and storage-association checks see the correct
+ // address rather than always returning the block base (offset 0).
+ symbol.set_size(0);
+ symbol.set_offset(offset_);
return 0;
}
std::size_t previousOffset{offset_};
diff --git a/flang/test/Lower/common-block-char0.f90 b/flang/test/Lower/common-block-char0.f90
new file mode 100644
index 0000000000000..02f2665d6faae
--- /dev/null
+++ b/flang/test/Lower/common-block-char0.f90
@@ -0,0 +1,36 @@
+! RUN: %flang_fc1 -emit-hlfir -o - %s | FileCheck %s
+
+! Test that CHARACTER*0 symbols in a COMMON block are assigned their correct
+! sequential offset rather than always offset 0 (the block base address).
+!
+! Block /blk/ layout:
+! offset 0 : ii1 (integer(8), 8 bytes)
+! offset 8 : zc0 (character*0, 0 bytes) <- zero-size, no storage consumed
+! offset 8 : ll1 (integer(8), 8 bytes)
+! Total: 16 bytes
+!
+! Before fix (compute-offsets.cpp): DoSymbol() returned early for zero-size
+! symbols without calling symbol.set_offset(), leaving zc0 stamped with
+! offset 0. This caused storage(%1[0]) for zc0 instead of storage(%1[8]).
+
+subroutine char0_common
+ integer(8) :: ii1
+ character*0 :: zc0
+ integer(8) :: ll1
+ common /blk/ ii1, zc0, ll1
+ call use(ii1, zc0, ll1)
+end subroutine
+
+! CHECK: fir.global common @blk_(dense<0> : vector<16xi8>) {alignment = 8 : i64} : !fir.array<16xi8>
+
+! CHECK-LABEL: func.func @_QPchar0_common
+
+! ii1 at offset 0
+! CHECK: %[[BASE:.*]] = fir.address_of(@blk_) : !fir.ref<!fir.array<16xi8>>
+! CHECK: hlfir.declare {{.*}} storage(%[[BASE]][0]) {uniq_name = "_QFchar0_commonEii1"}
+
+! ll1 at offset 8
+! CHECK: hlfir.declare {{.*}} storage(%[[BASE]][8]) {uniq_name = "_QFchar0_commonEll1"}
+
+! zc0 at offset 8 (not 0) -- key assertion
+! CHECK: hlfir.declare {{.*}} storage(%[[BASE]][8]) {uniq_name = "_QFchar0_commonEzc0"}
diff --git a/flang/test/Semantics/common-block-char0.f90 b/flang/test/Semantics/common-block-char0.f90
new file mode 100644
index 0000000000000..4210b28fb366e
--- /dev/null
+++ b/flang/test/Semantics/common-block-char0.f90
@@ -0,0 +1,35 @@
+! RUN: %python %S/test_errors.py %s %flang_fc1
+! Test that a zero-size CHARACTER in a COMMON block does not trigger a false
+! "cannot backward-extend COMMON block" error when it is referenced in an
+! EQUIVALENCE association.
+!
+! Block /blk/ layout:
+! offset 0 : i8 (integer(8), 8 bytes)
+! offset 8 : zc0 (character(0), 0 bytes)
+!
+! equivalence(c8(5:8), zc0) places c8(1) at offset 4 (= 8 - 4 bytes before zc0).
+
+subroutine p09
+ integer(8) :: i8
+ character(0) :: zc0
+ character(8) :: c8
+ common /blk/ i8, zc0
+ equivalence (c8(5:8), zc0)
+ call use(c8, i8)
+end subroutine
+
+! A genuine backward extension through a zero-size member must still error.
+! Block /blk2/ layout:
+! offset 0 : zc0 (character(0), 0 bytes)
+! offset 0 : i8 (integer(8), 8 bytes)
+!
+! equivalence(c8(5:8), zc0) would place c8(1) at offset -4 -- before the
+! block base -- which is a true backward extension and must be rejected.
+subroutine backward
+ integer(8) :: i8
+ character(0) :: zc0
+ character(8) :: c8
+ !ERROR: 'zc0' cannot backward-extend COMMON block /blk2/ via EQUIVALENCE with 'c8'
+ common /blk2/ zc0, i8
+ equivalence (c8(5:8), zc0)
+end subroutine
More information about the flang-commits
mailing list