Commit Graph
7954 Commits
Author SHA1 Message Date
Caolán McNamara 4aba7e41c1 put calc external data mappings under link update control
register each mapping as a LinkManager link, so its refresh goes through
the same update control as sheet links and area links. Wait until after
the infobar-controlled update mode is known to update.

Signed-off-by: Caolán McNamara <caolan.mcnamara@collabora.com>
Change-Id: I6710d4bdf3de6e002365d75c911b69076a054da8
Reviewed-on: https://gerrit.collaboraoffice.com/c/core/+/7058
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
(cherry picked from commit b72d760465c857eb5dd10cdc45b107c49bb0caec)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/208319
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Tested-by: Jenkins
2026-07-21 08:59:06 +02:00
Justin Luth 1bfad0e536 tdf#160781 sc SearchStyle: byRow and byCol were switched around
This code is basically untouched since initial import.

For some reason, searching for patterns handled by Row
as if it was by Column - the opposite of text searching.

This patch fixes that.

Thanks to Julien Nabet who gave an initial try
and identified that looping again didn't work.

Change-Id: Ie6daa67e7d94bb1a5b8cd58158d20f1a383a7d77
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/208200
Tested-by: Jenkins
Reviewed-by: Justin Luth <jluth@mail.com>
2026-07-20 23:20:26 +02:00
Justin Luth 6398132373 tdf#163888 sc ReplaceAllStyle: only replace for MultiMark in this tab
This fixes a LO 3.5 regression
from commit 0783e78de2
    Let's avoid modifying the selection data during search and replace

The problem was that only the first sheet's range was used,
and it was being applied to every sheet that had a match.
(Thus one reason why selection data was modified during S&R).

I would have LOVED to have some functions like ScRange(SCTAB)
or GetIntersectedRange(SCTAB). I almost created this one,
but the compile took so long, and it needed ScDocument passed to it
which made it look ugly - so I didn't bother in the end.

Change-Id: I6abc25fd4f7002d190632fe33963fdeb1af4b1ed
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/208231
Reviewed-by: Justin Luth <jluth@mail.com>
Tested-by: Jenkins
2026-07-20 23:18:56 +02:00
Justin Luth 6de09b5027 tdf#160781 sc SearchAndReplace: also loop by Column backwards
If you search by Row or Column forwards,
you will loop back to the beginning.
If you search by Row backwards,
you will loop back to the end.

This patch adds looping when searching by Column backwards,
and it also works when 'All Sheets' is checked.

Change-Id: I23252671b47fe05953cfd386a46b1c065d512127
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/208204
Reviewed-by: Justin Luth <jluth@mail.com>
Tested-by: Jenkins
2026-07-20 23:16:29 +02:00
Tomaž Vajngerl bfc9cfdecf Remove the lp_solve solver, which CoinMP makes redundant
The Lpsolve solver and the CoinMP solver are both used for the same
thing: a linear model, with optional integer variables by branch
and bound. CoinMP (CLP plus CBC) is the more capable and better
maintained of the two, so the lp_solve one adds a second bundled
dependency and a parallel copy of the solver code for no capability
the other lacks.

Remove the LpsolveSolver component, the bundled lp_solve external
(and its colamd dependency, which only lp_solve used), and all the
build, configure, packaging and license references to them.

A document may still name com.sun.star.comp.Calc.LpsolveSolver as
its engine. SolverSettings now reads that name as the CoinMP
solver, which solves the same model, so such documents keep
working.

The Calc solver test that exercised the engine now uses CoinMP. Its
knapsack model has a single optimal total value of 6987, which fills
the weight capacity of 1000 exactly and which CoinMP finds. The
lp_solve run had returned a suboptimal 6981, so the test now expects
the true optimum.

The build setup changes only take effect after re-running autogen.

Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>
Change-Id: Ia14d8c491779873da6b0157aa524056275adf8f5
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/3810
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
(cherry picked from commit e77738a7ca7d44fd9d1f852e26d46e3a6d60467b)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/208038
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
2026-07-14 12:49:42 +02:00
Khaled Hosny bc48579c2e tdf#172647: Store Calc cell fonts by their typographic names
Change-Id: Ib9f013f8e96e0a0c33f46733bd4dea9f577f77ff
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207552
Tested-by: Khaled Hosny <khaled@libreoffice.org>
Reviewed-by: Khaled Hosny <khaled@libreoffice.org>
2026-07-14 00:15:51 +02:00
Xisco Fauli e3a3958242 cid#1696360: silence Dereference after null check
Change-Id: I731c47183dc01dbeb286b974007d04c5c0da86ca
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207953
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
2026-07-10 23:05:49 +02:00
Tomaž Vajngerl dd2decfe19 sc: recreate a pasted table only when formulas are pasted
CopyFromClip() recreates a named table the copy fully covered so the
structured-reference tokens in the pasted formulas can resolve
against it. It ran that step for any content paste, so a values-only
paste also registered the table, with its autofilter and style, even
though it carries no formula that would reference the table.

Gate the table recreation on the formula content flag, so a
values-only paste leaves the destination without a table.

Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>
Change-Id: I8bf7b30ef4fc415229d05f57955ac9d6cf65910e
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/5097
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
Reviewed-by: Balázs Varga <balazs.varga@collabora.com>
(cherry picked from commit c0ec48adf51d34a50469b78df4136aaaa1dce074)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207946
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
2026-07-10 23:04:26 +02:00
Tomaž Vajngerl 499ca3e23e sc: carry a table into the clipboard only from a copied range
CopyToClip() copies named database ranges into the clipboard document
through CopyDBsToClip(), which decided whether to carry a table by
testing it against the bounding box of the copied area. For a
non-contiguous selection the bounding box also covers the gaps
between the selected ranges, so a table sitting in such a gap was
carried even though none of its cells were copied.

Test the table against the actually copied ranges instead of their
bounding box, so a table that lies entirely in a gap is left out.

Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>
Change-Id: I1c8663e5190247dae0edf3878efe37186a7f6a4d
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/5095
Reviewed-by: Balázs Varga <balazs.varga@collabora.com>
Tested-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
(cherry picked from commit 37543af628671f723c9a661e2add91d6bc641591)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207944
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
2026-07-10 23:04:00 +02:00
Tomaž Vajngerl 21221fe1f0 sc: keep table column names when re-anchoring a pasted table
CopyDBsFromClip() re-anchors a fully-copied named table at the
paste location with MoveTo(). Changing the area resets the table
column names, because the header range moves, so the names the
clipboard copy had carried were discarded. A structured reference
could then no longer resolve a column by name against the pasted
table, and its value became #REF!.

Save the carried names before the move and set them again
afterwards. The paste is a pure translation, so the names map to
the same columns as before.

Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>
Change-Id: Ib5e836daa4c9739b38fd4fa8c8dc3d58c6793b75
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/5092
Tested-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
Reviewed-by: Balázs Varga <balazs.varga@collabora.com>
(cherry picked from commit 5f08075266d8337a91f0ed3c3f4a1a18d81d03d8)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207941
Tested-by: Xisco Fauli <xiscofauli@libreoffice.org>
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
2026-07-10 14:48:01 +02:00
Tomaž Vajngerl 6612d4f785 sc: add the # postfix operator for spilled-range references
A1# is the postfix counterpart of the @ prefix. When A1 is
the origin of a dynamic-array formula spilled into A1:A4, A1#
refers to the whole spill range, so SUM(A1#) totals the four
values and ROWS(A1#) returns 4.

The new opcode ocSpill sits in the unary-operator range. The
tokenizer produces it from a bare # after a reference or
value. Otherwise # stays the start of a #REF! or #NAME!
token. The compiler routes it through PostOpLine so it
follows its operand in the RPN.

ScSpilledRange pushes the spill range as an ScMatrixRangeToken
so aggregating functions see the whole range, and ISREF
reports it as a reference. A master yields its matrix. A
plain number, string, or non-master matrix slot yields the
the cell value.

A freshly typed =A1# counts as an array result, so it
promotes to a dynamic-array master and spills again. A cell
that does not promote collapses the range by implicit
intersection to the row-aligned value, or #VALUE! outside the
range, keeping that cell's number format.

Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>
Change-Id: Idf2752af3f7575f6bc95b940344aa365415e4a2f
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/5785
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
Tested-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
(cherry picked from commit 9b97b0fc91bce4b8726ea210347e8ea84270e148)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207904
Tested-by: Xisco Fauli <xiscofauli@libreoffice.org>
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Tested-by: Jenkins
2026-07-10 01:08:46 +02:00
Caolán McNamara 96691462de crashtesting: re-search lagging columns past nRow in the attr iterator
ScHorizontalAttrIterator only reinitialises when nRow passes the global
nMinNextEnd, so a column can be more than one run behind and a single ++
leaves its run end below nRow, tripping the "Sequence out of order"
assert. Re-search with ScAttrArray::Search instead, as the first row does.

forum-mso-en4-146187.xlsx aborted before this when saved to xls or xlsx.

Signed-off-by: Caolán McNamara <caolan.mcnamara@collabora.com>
Change-Id: I3065114f04b976a72ef44634bc981547fff4a87b
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/4721
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
Reviewed-by: Noel Grandin <noel.grandin@collabora.com>
(cherry picked from commit f48aa0234af8a16aecb20f32c9584226fc928d3f)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207396
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
2026-07-10 01:08:20 +02:00
Tomaž Vajngerl b57cc044fe sc: auto-spill UI-typed CHOOSE and LET when a branch is an array
intendsArrayResultInRange walked branch slices for the IF
family but bailed on ocChoose and ocLet, so a plain-cell
CHOOSE or LET never auto-promoted even when one of its
branches produced a multi-cell array.

Treat ocChoose and ocLet like the IF family. The jump token
layout is identical, so the same branch-walk picks the right
slices.

LET conflates a binding value being array with the LET result
being array. The typical LET(x, A1:A3, x*2) propagates the
array shape through the body, so this over-approximation
matches the user's intent. A false positive enters CSE mode
for a scalar result, and the spill check catches it.

testAutoSpillFromChooseAndLet enters a CHOOSE that picks a
range branch and a LET that doubles a range binding.

Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>
Change-Id: I3339c748be32ccefa23c9f069f917299ec8ffe5c
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/5537
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
Tested-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
(cherry picked from commit 029292a4b5621f73401145b0269682e286eac98b)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207870
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Tested-by: Xisco Fauli <xiscofauli@libreoffice.org>
2026-07-09 17:09:16 +02:00
Tomaž Vajngerl ee4bd7f201 sc: ignore the dynamic-array master flag when @ ends the RPN
An @-prefixed formula opts out of dynamic-array spilling, but
the OOXML import still arrives with cm="1" on such cells. The
cell then turned into #SPILL! because the spill check ran
against the 1x1 declared range.

Reject the dynamic-array master request when the RPN ends with
@. The @ collapses the array at interpret time.

testAtFormulaIgnoresDynamicArrayMasterFlag checks that
SetDynamicArrayMaster has no effect on an @-prefixed cell.

Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>
Change-Id: I33322626a32893287c8859580a719dbeb9b915b4
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/5490
Reviewed-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
Tested-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
(cherry picked from commit 02c7d85b6a0aa6269582072642501148da2d092d)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207867
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
2026-07-09 17:08:36 +02:00
Caolán McNamara fcfec741ef crashtesting: don't parallelize a conditional sum that grows its range
A three argument SUMIF or AVERAGEIF grows a small sum range to the shape of
the criteria range. It then reads cells that no reference token names.

The parallel-calc dependency scan only follows reference tokens, so it
misses those cells, and a worker hits one uninterpreted and trips the
group-calc assert.

Drop that form, like the nearby ocRange guard. The two argument form
sums the criteria range itself and stays parallel.

  sc/inc/formulacell.hxx:514: void ScFormulaCell::MaybeInterpret():
      Assertion `!rDocument.IsThreadedGroupCalcInProgress()' failed.

seen reloading forum-mso-en4-35616.xlsx saved as xls, M9 is
=IFERROR(SUMIF(B9:E33,B9,L9:L33)/SUM(L9:L33),0): the sum range grows from
L9:L33 to L9:O33 and reads the uninterpreted O9.

Only started asserting once the callables work landed, which doesn't touch
this path, so that seems to have uncovered an older gap.

maybe since:

    commit 837cf12bc45c72e08c4629d07a43c27763b263b2
    Date:   Sat Jun 20 23:28:17 2026 -0400

        Implemented callables as first-class objects in Calc formulas

Signed-off-by: Caolán McNamara <caolan.mcnamara@collabora.com>
Change-Id: I861c7f645a65cd0c7564ccb96bf040e401cd2f08
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/6160
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
Reviewed-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
(cherry picked from commit 04ad1ed4ba2c9a78ed260fc4e18249a40137db94)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207824
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
2026-07-09 11:42:23 +02:00
Ben Urban 76c9c81b02 Implemented functions which rely on callables
Add BYCOL(tdf#164508), BYROW(tdf#164509), MAKEARRAY(tdf#164511),
MAP(tdf#164512), REDUCE(tdf#164513), SCAN(tdf#161428) formula
functions, which are usually used together with LAMBDA and are
important for interoperability with other Office suites.

Change-Id: I7eb5a992a113638fdadf0cf61592c082094fb44f
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/205979
Tested-by: Xisco Fauli <xiscofauli@libreoffice.org>
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
2026-07-09 08:44:48 +02:00
Ben Urban 331e346fb1 Implemented LAMBDA and ISOMITTED for Calc
Added LAMBDA (tdf#138749) function
Added ISOMITTED (tdf#164510) function
Rewrote LET to work with the new LAMBDA

Change-Id: I45dbf18c43e56c788848f60cd8380dd8d7c476b5
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/206265
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Tested-by: Xisco Fauli <xiscofauli@libreoffice.org>
2026-07-09 08:43:28 +02:00
Ben Urban 3bdd856e9f Implemented callables as first-class objects in Calc formulas
Three types of callables are available:

* Built-in functions (tdf#164507)

* External functions

* Macro functions

Change-Id: I6311c9412db650cfeb1100497e4ccdc39662c350
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/206264
Tested-by: Xisco Fauli <xiscofauli@libreoffice.org>
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
2026-07-09 08:42:21 +02:00
Tomaž Vajngerl 3b880b81f7 sc: scope auto-promotion eligibility to freshly typed cells
The mbAutoDynamicArrayEligible bit marks a cell as allowed to
auto-promote to a dynamic-array master on its first interpret.
The copy constructor propagated the bit, so a paste or fill
clone of a still-eligible source inherited the eligibility and
could auto-promote at the destination position.

Clear the bit on copy and move the explicit set onto the cell
after the local-to-document copy in the UI entry path. The
clone starts non-eligible, and only the freshly typed cell
handed to the document keeps the bit. A paste no longer leaks
into auto-promotion.

Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>
Change-Id: I164cdf2411bb4d31148c3a73e1e70440c5f604dc
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/5194
Tested-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
(cherry picked from commit 8b46008b1f709f06cc88040d674659e15ea6f53b)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207788
Tested-by: Jenkins
Tested-by: Xisco Fauli <xiscofauli@libreoffice.org>
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
2026-07-08 23:47:06 +02:00
Tomaž Vajngerl 936fb78484 sc: keep multi-cell ranges unfolded in the @-restore compiler
XLS-imported cells arrive without an RPN, so the @-restore path
compiles the parse to RPN on demand. That on-demand compile
used to run with the implicit-intersection optimisation on, and
multi-cell range pushes were rewritten to single-cell picks
before the array-intent walk could see them. A plain =A1:A4+10
reloaded from an XLS file then walked as a scalar expression
and never got the @ marker restored.

Disable the optimisation on the on-demand compile. The walk
now sees range pushes as ranges, the binary + with a range
operand walks as array, and the @ marker is restored. Shapes
like =@TRANSPOSE(B1:B4) keep working through the matrix-
function branch.

Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>
Change-Id: I92879aa6604864dfc5a5b41999177dbfcffce21a
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/5192
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
Tested-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
(cherry picked from commit 196cf615e544e62add27fd5eeb42b1cc5f47fbc2)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207786
Tested-by: Xisco Fauli <xiscofauli@libreoffice.org>
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
2026-07-08 23:46:44 +02:00
Tomaž Vajngerl ea5d5dceab sc: keep @ on each operand from propagating array intent
The pre-Interpret walk that decides whether a freshly typed
formula should auto-promote to a dynamic-array master treats
the @ implicit-intersection operator as a transparent unary.
A formula whose every operand carries an @ then walks as
array-and-array and the cell promotes to a master, even though
the interpreter evaluates each @ operand as a scalar. The
displayed value is correct, but the saved file carries the
master flag on a cell that should stay plain.

Treat ocSingleValue as forcing scalar in the walk. The result
of @ is scalar, so the array-ness of its operand no longer
propagates through it.

Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>
Change-Id: Ifa2a676bc62a2733b17b728773e6693669ad7717
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/5106
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
(cherry picked from commit fbc6b948f675f7787cbe48e55c5f55302eef5e32)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207785
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Tested-by: Xisco Fauli <xiscofauli@libreoffice.org>
2026-07-08 20:59:01 +02:00
Tomaž Vajngerl 53b3f5a6f8 sc: spill an IF formula whose branches are multi-cell ranges
The pre-Interpret walk that decides whether a freshly typed
formula should auto-promote to a dynamic-array master used to
bail on every jump command. An IF whose branches are multi-
cell ranges then stayed a plain single-cell formula and only
the upper-left of the chosen branch showed in the cell.

The walk now descends into the branches of IF, IFERROR and
IFNA, reading the branch offsets off the jump token. The
formula promotes to a dynamic-array master and spills when any
branch produces an array.

CHOOSE and LET still bail. Their jump-offset layouts differ
from the IF family and need dedicated handling.

Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>
Change-Id: I75a76a2af3634588d76c410e5487b4a87571f3ba
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/5105
Tested-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
(cherry picked from commit c1fa705be1b53ff677d70040e002bd5d9d7b84c2)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207784
Tested-by: Xisco Fauli <xiscofauli@libreoffice.org>
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
2026-07-08 20:58:48 +02:00
Tomaž Vajngerl 3c95eed2ba sc: promote UI-typed array formulas to dynamic-array masters
When the user types a formula that returns an array (UNIQUE,
TRANSPOSE, a range plus a range, ...) and presses Enter, the
cell now becomes a dynamic-array master. The array result
spills into the empty cells to the right and below the typed
cell. The user no longer has to press Ctrl+Shift+Enter to get
array behaviour.

Formulas loaded from a file and formulas created from a macro
keep their old single-value behaviour, so existing documents
are not affected.

A new per-cell bit, mbAutoDynamicArrayEligible, marks a cell
as allowed to promote. The view code sets it on freshly typed
formulas. The importers and the macro entry path leave it off.

When such a cell first calculates, the formula tokens are
walked in execution order to ask the question: does this
formula produce an array result? If yes, the cell switches to
dynamic-array master mode before the calculation runs, so the
array result is kept and the cells to the right and below get
filled in.

The walk tracks whether the value sitting on the stack at each
step is an array or a scalar:

 - Pushing a multi-cell range or an inline matrix puts an
   array on the stack.
 - An operator like + or * keeps the result an array if any
   operand was an array.
 - A function known to return an array (UNIQUE, TRANSPOSE,
   MMULT, SEQUENCE, ...) puts an array on the stack. Other
   functions reduce to a scalar.
 - Branching functions like IF, CHOOSE, IFERROR and LET do
   not fit this simple model, so the walk gives up and the
   cell stays a plain single-cell formula.

A formula that begins with the @ implicit-intersection
operator (=@UNIQUE(...)) opts out of promotion. Cells that
are part of a formula group share a single compiled formula
and stay single-cell so the group is not broken.

Ctrl+Shift+Enter still produces a classic static array master.
The shortcut now routes straight to the matrix-entry code, so
the auto-detect described above does not interfere.

The formula compiler has an optimization that rewrites a
multi-cell range as a single-cell pick when the formula sits
in a single-cell context. For example =A1:A4 typed in row 2
becomes =A2 before evaluation. That is the long-standing
implicit-intersection rule.

For typed input the optimization has to be off, otherwise the
multi-cell range disappears from the formula before the walk
can see it. The optimization stays in place everywhere else,
and the engine still applies implicit intersection at run
time when the cell remains a plain single-cell formula.

XLSX export

XLSX marks a dynamic-array master with cm="1" on the cell.
The exporter used to fall back to "matrix master plus a
dynamic-array function" when the explicit flag was missing.
The fallback is now removed. Every cell that should export as
dynamic carries the flag explicitly, set by the importer or
by the UI entry path.

One trade-off: a Ctrl+Shift+Enter (CSE) array of a dynamic-
array function imported from an XLSX file that has no cm="1"
marker no longer round-trips as dynamic. The cell flag is now
the single source of truth.

Tests

Tests cover the array-intent walk for =MINVERSE(...), ={1;2},
={1;2}+3, ={1;2}+{3;4}, ={1;2}+A1, =ABS({-1;-2}), =A1:A2,
=A2:A5+B2:B5, a long chain of binary additions over the same
range, a range times a scalar, =IF(...) with array branches,
and =SUM(...) over a range as the scalar case.

Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>
Change-Id: Icb4b5e108634cd1529ac829cb34865c56ed8ec02
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/4684
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
(cherry picked from commit c3d67d3ec81621c385744fac7fd7a722084a122f)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207219
Tested-by: Xisco Fauli <xiscofauli@libreoffice.org>
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
2026-07-08 20:58:41 +02:00
Stephan Bergmann 1df02d7afa Fix heap-buffer-overflow in formula::FormulaTokenArray::Add
ScTokenArray::Clone and CloneValue have always allocated the parse-token array
pCode to hold exactly nLen entries, but unlike Assign they left mbFinalized at
false.  And FormulaTokenArray::Add assumes that a non-finalized pCode has room
for at least MAX_FAST_TOKENS entries.  Which now started to break with
a21f6a3a0eae72fef90576d249d96dc00beeb2c5 "sc: round-trip dynamic-array masters
and @ through ODF",

> ==611420==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7befc900e420 at pc 0x7b8f762c6d53 bp 0x7ffdf0776f90 sp 0x7ffdf0776f88
> WRITE of size 8 at 0x7befc900e420 thread T0
>  #0 in formula::FormulaTokenArray::Add(formula::FormulaToken*) at engine/formula/source/core/api/token.cxx:772:25
>  #1 in ScTokenArray::AddRawToken(ScRawToken const&) at engine/sc/source/core/tool/token.cxx:2004:12
>  #2 in ScTokenArray::AddOpCode(OpCode) at engine/sc/source/core/tool/token.cxx:2224:12
>  #3 in (anonymous namespace)::prependImplicitIntersection(ScTokenArray&) at engine/sc/source/core/data/formulacell.cxx:1654:49
>  #4 in ScFormulaCell::ResolveImplicitIntersection(ScTokenArray&, ScDocument&, ScAddress const&) at engine/sc/source/core/data/formulacell.cxx:2716:9
>  #5 in ImportExcel::Formula(XclAddress const&, unsigned short, unsigned short, double, bool) at engine/sc/source/filter/excel/excform.cxx:127:17
>  #6 in ImportExcel::Formula25() at engine/sc/source/filter/excel/excform.cxx:72:5
>  #7 in ImportExcel8::Read() at engine/sc/source/filter/excel/read.cxx:1184:49
>  #8 in ScFormatFilterPluginImpl::ScImportExcel(SfxMedium&, ScDocument*, EXCIMPFORMAT) at engine/sc/source/filter/excel/excel.cxx:255:35
>  #9 in ScDocShell::ConvertFrom(SfxMedium&) at engine/sc/source/ui/docshell/docsh.cxx:1329:52
>  #10 in SfxObjectShell::DoLoad(SfxMedium*) at engine/sfx2/source/doc/objstor.cxx:777:27
>  #11 in ScFilterTestBase::loadDoc(rtl::OUString const&, rtl::OUString const&, rtl::OUString const&, rtl::OUString const&, SfxFilterFlags, SotClipboardFormatId, int) at engine/sc/qa/unit/helper/scfiltertestbase.cxx:40:21
>  #12 in ScFiltersTest::load(rtl::OUString const&, rtl::OUString const&, rtl::OUString const&, SfxFilterFlags, SotClipboardFormatId, unsigned int) at engine/sc/qa/unit/filters-test.cxx:68:31
>  #13 in non-virtual thunk to ScFiltersTest::load(rtl::OUString const&, rtl::OUString const&, rtl::OUString const&, SfxFilterFlags, SotClipboardFormatId, unsigned int) at engine/sc/qa/unit/filters-test.cxx
>  #14 in test::FiltersTest::recursiveScan(test::filterStatus, rtl::OUString const&, rtl::OUString const&, rtl::OUString const&, SfxFilterFlags, SotClipboardFormatId, unsigned int, bool) at engine/unotest/source/cpp/filters-test.cxx:132:20
>  #15 in test::FiltersTest::testDir(rtl::OUString const&, std::basic_string_view<char16_t, std::char_traits<char16_t>>, rtl::OUString const&, SfxFilterFlags, SotClipboardFormatId, unsigned int, bool) at engine/unotest/source/cpp/filters-test.cxx:157:5
>  #16 in ScFiltersTest::testCVEs() at engine/sc/qa/unit/filters-test.cxx:91:5
>
> 0x7befc900e420 is located 0 bytes after 64-byte region [0x7befc900e3e0,0x7befc900e420)
> allocated by thread T0 here:
>  #0 in operator new[](unsigned long) at /home/sberg/github.com/llvm/llvm-project/compiler-rt/lib/asan/asan_new_delete.cpp:111:37
>  #1 in ScTokenArray::Clone() const at engine/sc/source/core/tool/token.cxx:1901:24
>  #2 in ImportExcel::Formula(XclAddress const&, unsigned short, unsigned short, double, bool) at engine/sc/source/filter/excel/excform.cxx:126:70
>  #3 in ImportExcel::Formula25() at engine/sc/source/filter/excel/excform.cxx:72:5

Signed-off-by: Stephan Bergmann <stephan.bergmann@collabora.com>
Change-Id: I2ce67e89c24fee8e1bdfa7baf40ce02783637254
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/4962
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
Reviewed-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
(cherry picked from commit e4161389322e3f096e3b1537058a94e0636eaeaa)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207469
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Tested-by: Jenkins
2026-07-08 18:00:08 +02:00
Tomaž Vajngerl eb239f1a15 sc: round-trip dynamic-array masters through XLSX, strip @ on XLS
XLSX marks a dynamic-array master with cm="1" on the cell and a
matching dynamicArrayProperties metadata block. Both import and
export now travel through mbDynamicArrayMaster on the cell.

XLSX import plumbs the flag through the three formula paths.
XML_normal and XML_shared land in applyCellFormulas and
applySharedFormulas through setCellFormula. XML_array lands in
applyArrayFormulas through setCellArrayFormula. Each path sets
mbDynamicArrayMaster on the imported cell or on the matrix master.

XLSX export reads the flag in XclExpFormulaCell::SaveXml to drive
cm="1" and the dynamicArrayProperties block. The legacy pair of a
Ctrl+Shift+Enter (CSE) master that calls a dynamic-array function
stays as a fallback while the importers and the UI entry path are
being wired through.

XLS has no @ encoding and no dynamic-array marker. Save and load
mirror the ODF behaviour:
- The exporter strips ocSingleValue (alongside ocSpaces and
  ocWhitespace) in GetNextToken so the BIFF stream stays valid.
  The saved formula evaluates to the upper-left value the way XLS
  always did.
- The importer walks the just-built RPN of every plain non-array
  formula and prepends @ when the formula intends an array. The
  resolve runs before the formula cell is constructed, while the
  parse array is still mutable. The static helper compiles a
  missing RPN on demand so the array-intent walk has the post-fix
  order it needs.
- XLS array records keep the legacy CSE behaviour. They have no
  dynamic-array encoding, so loading them as static arrays matches
  what the file format can express.

Tests cover an XLSX import of Spill.xlsx, an XLSX round trip of the
same file, a direct-XML XLSX export check that the spilled master
at C2 keeps cm="1" and the dynamicArrayProperties metadata block,
and an XLS round trip of =@TRANSPOSE(B1:B4) where the @ reappears
after reload.

Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>
Change-Id: I30318bad4cdb50bbd92240fd71d70df0959a0eda
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/4664
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Tested-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
(cherry picked from commit 79eda1a177abf9a348dbc67c211b26cabd0cb4c1)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207218
Tested-by: Xisco Fauli <xiscofauli@libreoffice.org>
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
2026-07-08 18:00:00 +02:00
Noel Grandin f478a4f600 speedup ScTable::SetDrawPageSize
which calls GetColOffset() with a very large column value, which
causes it to loop, repeatedly searching the hidden-columns
data-structure. With large spreadsheets, this becomes expensive.

Change-Id: If1a1a7f85e2f36273e2de8da41be2756f52be8a5
Signed-off-by: Noel Grandin <noel.grandin@collabora.co.uk>
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/5764
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
Reviewed-by: Caolán McNamara <caolan.mcnamara@collabora.com>
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
(cherry picked from commit 86a8a9ec70c039a493986cf78abaa17882f49bd7)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207624
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
2026-07-06 10:47:56 +02:00
Xisco Fauli 4c553c887b cid#1696359: silence Resource leak
Change-Id: Iec639dac84cc0e7c733b9e0e625b4b9eb6717fc0
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207620
Reviewed-by: David Gilbert <freedesktop@treblig.org>
Tested-by: Jenkins
2026-07-05 00:11:58 +02:00
Caolán McNamara 855da692bc crashtesting: unshare formula cells the matrix import overwrites
ScDocumentImport::setMatrixCells places the matrix master and its
reference cells with raw cell-store set() calls. set() destroys the
cell it overwrites with no shared-formula bookkeeping, so a group
whose member dies that way is left with a stale length, or with a
dead top cell that the next Interpret of a surviving member
dereferences (formulacell.cxx:1560).

The xlsx import builds exactly such groups from stacked dynamic
arrays: the empty <f ca="1"/> spill placeholders of adjacent rows
compile to identical empty token arrays, and applyCellFormulas puts
vertical runs of identical formulas into one group. Materialising the
upper row's array then destroys the lower row's group top.

A member surviving its top cell's destruction became reachable since:

commit e4476c8072af0d825578f5222935718a159bb383
Date:   Wed May  6 23:33:16 2026 +0900

    sc: Preserve #SPILL! state through XLSX and ODS import

which keeps the cells of a spill-flagged array's range alive instead
of overwriting them all. Detach the doomed cell from its group before
each set().

Reproduced with forum-mso-en4-756517.xlsx and forum-mso-en4-756511.xlsx
from interop-test-files, soffice --headless --convert-to xlsx, dbgutil
build.

Signed-off-by: Caolán McNamara <caolan.mcnamara@collabora.com>
Change-Id: Ic347cee8c30b0d93919173a85fdd42cfd8a208e9
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/4723
Reviewed-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
(cherry picked from commit 2f74f677ce588c1ecbf3370c08a85ef94d49313e)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207397
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
2026-06-29 14:22:18 +02:00
Xisco Fauli 6f23441fec cid#1695393: Uncaught exception
Change-Id: I5dba5704407b4d01f10ae0921ea03f8152bc0551
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207368
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
2026-06-27 15:32:55 +02:00
Dr. David Alan Gilbert f148d2303f tdf#100244:sc: Use ScDPResultMemberSlim
Now that we have a complete ScDPResultMemberSlim use it
in ScDPResultDimension::AddMember() which is the case
used mostly in the non-lazy case.

As a whole this set takes tdf#100244 down to ~1.8G resident,
and tdf#126710 down to about 45G resident (down from 65G+).

Change-Id: I2a888437895ceeddcc06779f481729824820b62e
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/206508
Tested-by: Jenkins
Reviewed-by: David Gilbert <freedesktop@treblig.org>
2026-06-26 14:26:23 +02:00
Dr. David Alan Gilbert abc51bd0ec tdf#100244:sc:Add debug methods
Change-Id: I7247c7fa1ac32131f66ba05f11af859764bc4521
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/206507
Reviewed-by: David Gilbert <freedesktop@treblig.org>
Tested-by: Jenkins
2026-06-26 14:26:15 +02:00
Dr. David Alan Gilbert b50819a6da tdf#100244:sc:Implement GetParentLevel/Dim
Implement GetParentLevel, GetParentDim on ScDPResultMemberSlim
by asking the dimension we're part of.

Change-Id: Ie7d8871bd88ef9ce9256186594943f8fad90997c
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/206505
Tested-by: Jenkins
Reviewed-by: David Gilbert <freedesktop@treblig.org>
2026-06-26 14:25:51 +02:00
Dr. David Alan Gilbert 4ae76963d1 tdf#100244:sc:Implement 'promotion' code in Slim
When a method in ScDPResultMemmberSlim needs to become 'full', it calls
through the 'Promote' method here which then uses the previous code
added at the dimension to do most of the work.  This returns a pointer
to the new member.

Callers of member functions in Slim still have the pointer to the
Slim object, and so it's possible they will perform other method
calls on Slim using that pointer.  Thus a Slim method must check
if it's been promoted and if so call through GetPromote() to
use an existing promoted member.
(I think this might be avoidable by a nasty placement-new hack)

Change-Id: I1c9a3b0e07254c5d84c8f3ec8bc61a034a7b2dc8
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/206499
Reviewed-by: David Gilbert <freedesktop@treblig.org>
Tested-by: Jenkins
2026-06-26 14:24:50 +02:00
Dr. David Alan Gilbert 01e4f0559a tdf#100244:sc:Implement 'promotion' code in MemberDimension
When the ScDPResultMemmberSlim needs to become 'full', it calls
into the ScDPResultDimension it is part of.  This must create
the replacement object, and update the dimensions data structures
so that future uses will find the new object.

Change-Id: Id9155553719971f337505eee862bb0d83bafbcb4
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/206498
Reviewed-by: David Gilbert <freedesktop@treblig.org>
Tested-by: Jenkins
2026-06-26 14:24:41 +02:00
Dr. David Alan Gilbert c9b28f521d tdf#100244:sc: Create a ScDPResultMemberSlim
ScDPResultMemberSlim is a smaller version than ScDPResultMemberFull,
the hope is in a lot of cases we'll be able to use the Slim version
and save space overall.
It has just the data members we've found needed in most leaf cases.
(I have hopes we might be able to get a smaller version at some later
stage)

This can't be instantiated until all the virtual functions are
implemented in later patches.

Change-Id: I00f8556778271e511665719f3039ca36454c9f83
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/206497
Reviewed-by: David Gilbert <freedesktop@treblig.org>
Tested-by: Jenkins
2026-06-26 14:24:31 +02:00
Dr. David Alan Gilbert f9be211beb tdf#100244:sc:Move methods into base class
Move methods that don't access fields directly to the ScDPResultMember
base class.
Many of these methods were modified in the preceding commits to
go through accessors.

Change-Id: I333f81b3a9f64fe08a8c5a3b3c38423799383620
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/206496
Reviewed-by: David Gilbert <freedesktop@treblig.org>
Tested-by: Jenkins
2026-06-26 14:24:22 +02:00
Dr. David Alan Gilbert b073eb4bf2 tdf#100244:sc:Use a few more accessors
Use a few more accessors for the remaining cases we need to move
to the base class.

Change-Id: I8fe44f1dc4a22e4baa120da5462c041ade470bff
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/206495
Tested-by: Jenkins
Reviewed-by: David Gilbert <freedesktop@treblig.org>
2026-06-26 14:23:57 +02:00
Dr. David Alan Gilbert 3f3b40cbb7 tdf#100244:sc:Use GetParentDim() and GetDataRoot() accessors
Use GetParentDim() and GetDataRoot() in some of the ScDPResultMemberFull
methods that we would like to move to the base class.

Change-Id: Ic185fd3da14e2f965beae036dc11923cb2b2bae7
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/206494
Reviewed-by: David Gilbert <freedesktop@treblig.org>
Tested-by: Jenkins
2026-06-26 14:23:45 +02:00
Dr. David Alan Gilbert 99ea386da9 tdf#100244:sc:Use GetChildDimension() and GetResultData() accessors
Use GetChildDimension() and GetResultData() in some of the
ScDPResultMemberFull methods that we would like to move to the base
class.

Change-Id: I077f0db4255cf0d18dbf969cdfb6141f262e8329
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/206493
Tested-by: Jenkins
Reviewed-by: David Gilbert <freedesktop@treblig.org>
2026-06-26 14:23:28 +02:00
Dr. David Alan Gilbert c4dc39f253 tdf#100244:sc:Move simple methods to base class
For ScDPResultMember methods that don't access any members directly, we
can move those to the base class.

Change-Id: I58af3c23dcc83d85057ed86f6da1735aae37fb30
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/206492
Tested-by: Jenkins
Reviewed-by: David Gilbert <freedesktop@treblig.org>
2026-06-26 14:22:53 +02:00
Dr. David Alan Gilbert b2ff8daef5 tdf#100244:sc:Add ScDPResultMemberFull::ResetChilDimension()
The pChildDimension pointer is never arbitrarily set, but it is set
to a new ScDPResultDimension; abstract that into its own method.

Use it in InitFrom().

Change-Id: I9f85ff46645edd4e6932b7647aa58f552ec5d0e2
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/206491
Tested-by: Jenkins
Reviewed-by: David Gilbert <freedesktop@treblig.org>
2026-06-26 14:22:44 +02:00
Dr. David Alan Gilbert 9f01c44561 tdf#100244:sc: Insert base class under ScDPResultMember
Insert a base class underneath ScDPResultMember and make everything virtual.
'ScDPResultMember' is now the base class, and 'ScDPResultMemberFull'
is the now renamed full class.
(Doing it this way causes less changes everywhere else)

Move all the current definitions of functions in ScDPResultMember over
to Full; we'll move some of them back later.

This will grow the size of ScDPResultMemberFull for the vtable
pointer; however future patches will fight this back by
having a lightweight version.

llm-usage: A local gemma-4 created the base class for me with the prompt
 'This is a C++ coding problem.  The attached file is a C++ class
declaration;  please create me a base class for it, which has no data,
and where every function is virtual.'
I then tweaked the output.

Change-Id: Ia4051794f4cf279abe85b1d7bd31237d0672d469
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/206490
Reviewed-by: David Gilbert <freedesktop@treblig.org>
Tested-by: Jenkins
2026-06-26 14:21:41 +02:00
Tomaž Vajngerl 5286d91e80 sc: round-trip dynamic-array masters and @ through ODF
Import classifies each formula cell:
- Plain non-array, no coext:spill: the import-time walk over
  the freshly compiled RPN decides if the formula intends an
  array. If yes, prepend @ at the front of the parse and at
  the back of the RPN.
- Plain non-array + coext:spill="true": a master saved while in
  spill state. Comes back at 1x1 with the dynamic flag, the
  position marked spilled. The next interpret re-checks the
  blockers.
- Array formula (matrix dims): static array master by default.
  coext:spill="true" promotes it to a dynamic-array master.
  Legacy Ctrl+Shift+Enter (CSE) arrays without the marker keep
  their static iteration-and-pad behaviour.

Export reverses:
- ODF always strips @ on save. The @ is an in-memory marker
  only. OOXML and the UI grammar keep it.
- Dynamic master: coext:spill="true" in extended ODF, matrix
  dims as before. In spill state, write as plain non-array with
  coext:spill="true".
- Static array master: matrix dims, no coext:spill.

GetFormula skips the {} wrapping for dynamic-array masters so
they read back as plain formulas. Static array masters keep {}.

XML_SPILL is added to the xmloff token machinery and the ODF
extension schema (OpenDocument-v1.4+libreoffice-schema.rng)
gains coext:spill on table-cell.

Tests cover each import shape, the FODS export of regular and
spilled masters, the @ insertion on CompileXML, and the @
stripping at the formula-compiler level. ArrayFormulasStatic.ods
is a legacy fixture whose B1 = AND(C4:C52) summarises 49 per-row
value checks. The test runs the grid on import and after an ODS
round trip and confirms plain bare-range cells gain @ while the
five matrix masters stay static, keep their {} wrapping, and
get no coext:spill in the saved XML.

Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>
Change-Id: Ib8ae345528185c824415ec5d039b6d5cf0d7eac8
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/4663
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Tested-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
(cherry picked from commit a21f6a3a0eae72fef90576d249d96dc00beeb2c5)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207171
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Tested-by: Jenkins
2026-06-24 00:04:16 +02:00
Stephan Bergmann 6c22a1050e This bogus -Warray-bounds still hits with GCC 17
Signed-off-by: Stephan Bergmann <stephan.bergmann@collabora.com>
Change-Id: I986acdaee26da6b684afc51955ab658a0674d309
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/4853
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
Reviewed-by: Michael Stahl <michael.stahl@collabora.com>
(cherry picked from commit 78330ecdc4f447a47cde4afe64e55dfab061ef27)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207169
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
2026-06-23 12:27:24 +02:00
Stephan Bergmann 60fdd8f4f8 Silence some more spurious -Werror=array-bounds=
seen at least with GCC 16 trunk and --enable-optimized,

> In file included from /usr/include/c++/16/bits/char_traits.h:59,
>                  from /usr/include/c++/16/ios:44,
>                  from /usr/include/c++/16/bits/ostream.h:43,
>                  from /usr/include/c++/16/ostream:42,
>                  from engine/include/rtl/ustring.hxx:30,
>                  from engine/include/vcl/ctrl.hxx:23,
>                  from engine/include/vcl/InterimItemWindow.hxx:13,
>                  from engine/include/svtools/scrolladaptor.hxx:24,
>                  from engine/dbaccess/source/ui/inc/JoinTableView.hxx:21,
>                  from engine/dbaccess/source/ui/inc/QueryTableView.hxx:21,
>                  from engine/dbaccess/source/ui/querydesign/QueryTableView.cxx:20:
> In function ‘constexpr void std::destroy_at(_Tp*) [with _Tp = dbaui::OQueryTableWindowData]’,
>     inlined from ‘constexpr void std::_Destroy(_Tp*) [with _Tp = dbaui::OQueryTableWindowData]’ at /usr/include/c++/16/bits/stl_construct.h:164:22,
>     inlined from ‘static constexpr void std::allocator_traits<std::allocator<void> >::destroy(allocator_type&, _Up*) [with _Up = dbaui::OQueryTableWindowData]’ at /usr/include/c++/16/bits/alloc_traits.h:859:17,
>     inlined from ‘void std::_Sp_counted_ptr_inplace<_Tp, _Alloc, _Lp>::_M_dispose() [with _Tp = dbaui::OQueryTableWindowData; _Alloc = std::allocator<void>; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:682:35,
>     inlined from ‘void std::_Sp_counted_base<_Lp>::_M_release() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:423:18,
>     inlined from ‘void std::_Sp_counted_base<_Lp>::_M_release() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:392:5,
>     inlined from ‘std::__shared_count<_Lp>::~__shared_count() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1136:21,
>     inlined from ‘std::__shared_ptr<_Tp, _Lp>::~__shared_ptr() [with _Tp = dbaui::OQueryTableConnectionData; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1610:7,
>     inlined from ‘std::shared_ptr<dbaui::OQueryTableConnectionData>::~shared_ptr()’ at /usr/include/c++/16/bits/shared_ptr.h:175:11,
>     inlined from ‘void {anonymous}::addConnections(dbaui::OQueryTableView*, const dbaui::OQueryTableWindow&, const dbaui::OQueryTableWindow&, const com::sun::star::uno::Reference<com::sun::star::container::XNameAccess>&)’ at engine/dbaccess/source/ui/querydesign/QueryTableView.cxx:174:5:
> /usr/include/c++/16/bits/stl_construct.h:88:25: error: array subscript ‘dbaui::OQueryTableWindowData[0]’ is partly outside array bounds of ‘unsigned char [104]’ [-Werror=array-bounds=]
>    88 |         __location->~_Tp();
>       |         ~~~~~~~~~~~~~~~~^~
> In file included from /usr/include/c++/16/x86_64-redhat-linux/bits/c++allocator.h:33,
>                  from /usr/include/c++/16/bits/allocator.h:46,
>                  from /usr/include/c++/16/string:46,
>                  from /usr/include/c++/16/bits/locale_classes.h:43,
>                  from /usr/include/c++/16/bits/ios_base.h:43,
>                  from /usr/include/c++/16/ios:46:
> In member function ‘constexpr _Tp* std::__new_allocator<_Tp>::allocate(size_type, const void*) [with _Tp = std::_Sp_counted_ptr_inplace<dbaui::OQueryTableConnectionData, std::allocator<void>, __gnu_cxx::_S_atomic>]’,
>     inlined from ‘constexpr _Tp* std::allocator< <template-parameter-1-1> >::allocate(std::size_t) [with _Tp = std::_Sp_counted_ptr_inplace<dbaui::OQueryTableConnectionData, std::allocator<void>, __gnu_cxx::_S_atomic>]’ at /usr/include/c++/16/bits/allocator.h:206:40,
>     inlined from ‘static constexpr _Tp* std::allocator_traits<std::allocator<_CharT> >::allocate(allocator_type&, size_type) [with _Tp = std::_Sp_counted_ptr_inplace<dbaui::OQueryTableConnectionData, std::allocator<void>, __gnu_cxx::_S_atomic>]’ at /usr/include/c++/16/bits/alloc_traits.h:638:28,
>     inlined from ‘std::__allocated_ptr<_Alloc> std::__allocate_guarded(_Alloc&) [with _Alloc = allocator<_Sp_counted_ptr_inplace<dbaui::OQueryTableConnectionData, allocator<void>, __gnu_cxx::_S_atomic> >]’ at /usr/include/c++/16/bits/allocated_ptr.h:103:69,
>     inlined from ‘std::__shared_count<_Lp>::__shared_count(_Tp*&, std::_Sp_alloc_shared_tag<_Alloc>, _Args&& ...) [with _Tp = dbaui::OQueryTableConnectionData; _Alloc = std::allocator<void>; _Args = {const std::shared_ptr<dbaui::OTableWindowData>&, const std::shared_ptr<dbaui::OTableWindowData>&}; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1034:9,
>     inlined from ‘std::__shared_ptr<_Tp, _Lp>::__shared_ptr(std::_Sp_alloc_shared_tag<_Tp>, _Args&& ...) [with _Alloc = std::allocator<void>; _Args = {const std::shared_ptr<dbaui::OTableWindowData>&, const std::shared_ptr<dbaui::OTableWindowData>&}; _Tp = dbaui::OQueryTableConnectionData; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1812:14,
>     inlined from ‘std::shared_ptr<_Tp>::shared_ptr(std::_Sp_alloc_shared_tag<_Tp>, _Args&& ...) [with _Alloc = std::allocator<void>; _Args = {const std::shared_ptr<dbaui::OTableWindowData>&, const std::shared_ptr<dbaui::OTableWindowData>&}; _Tp = dbaui::OQueryTableConnectionData]’ at /usr/include/c++/16/bits/shared_ptr.h:463:59,
>     inlined from ‘std::shared_ptr<std::_NonArray<_Tp> > std::make_shared(_Args&& ...) [with _Tp = dbaui::OQueryTableConnectionData; _Args = {const shared_ptr<dbaui::OTableWindowData>&, const shared_ptr<dbaui::OTableWindowData>&}]’ at /usr/include/c++/16/bits/shared_ptr.h:1066:39,
>     inlined from ‘void {anonymous}::addConnections(dbaui::OQueryTableView*, const dbaui::OQueryTableWindow&, const dbaui::OQueryTableWindow&, const com::sun::star::uno::Reference<com::sun::star::container::XNameAccess>&)’ at engine/dbaccess/source/ui/querydesign/QueryTableView.cxx:127:111:
> /usr/include/c++/16/bits/new_allocator.h:162:75: note: at offset 16 into object of size 104 allocated by ‘operator new’
>   162 |           return static_cast<_Tp*>(_GLIBCXX_OPERATOR_NEW(__n * sizeof(_Tp)));
>       |                                                                           ^
> In function ‘constexpr void std::destroy_at(_Tp*) [with _Tp = dbaui::OQueryTableWindowData]’,
>     inlined from ‘constexpr void std::_Destroy(_Tp*) [with _Tp = dbaui::OQueryTableWindowData]’ at /usr/include/c++/16/bits/stl_construct.h:164:22,
>     inlined from ‘static constexpr void std::allocator_traits<std::allocator<void> >::destroy(allocator_type&, _Up*) [with _Up = dbaui::OQueryTableWindowData]’ at /usr/include/c++/16/bits/alloc_traits.h:859:17,
>     inlined from ‘void std::_Sp_counted_ptr_inplace<_Tp, _Alloc, _Lp>::_M_dispose() [with _Tp = dbaui::OQueryTableWindowData; _Alloc = std::allocator<void>; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:682:35,
>     inlined from ‘void std::_Sp_counted_base<_Lp>::_M_release() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:423:18,
>     inlined from ‘void std::_Sp_counted_base<_Lp>::_M_release() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:392:5,
>     inlined from ‘std::__shared_count<_Lp>::~__shared_count() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1136:21,
>     inlined from ‘std::__shared_ptr<_Tp, _Lp>::~__shared_ptr() [with _Tp = dbaui::OQueryTableConnectionData; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1610:7,
>     inlined from ‘std::shared_ptr<dbaui::OQueryTableConnectionData>::~shared_ptr()’ at /usr/include/c++/16/bits/shared_ptr.h:175:11,
>     inlined from ‘virtual void dbaui::OQueryTableView::AddConnection(const dbaui::OJoinExchangeData&, const dbaui::OJoinExchangeData&)’ at engine/dbaccess/source/ui/querydesign/QueryTableView.cxx:558:5:
> /usr/include/c++/16/bits/stl_construct.h:88:25: error: array subscript ‘dbaui::OQueryTableWindowData[0]’ is partly outside array bounds of ‘unsigned char [104]’ [-Werror=array-bounds=]
>    88 |         __location->~_Tp();
>       |         ~~~~~~~~~~~~~~~~^~
> In member function ‘constexpr _Tp* std::__new_allocator<_Tp>::allocate(size_type, const void*) [with _Tp = std::_Sp_counted_ptr_inplace<dbaui::OQueryTableConnectionData, std::allocator<void>, __gnu_cxx::_S_atomic>]’,
>     inlined from ‘constexpr _Tp* std::allocator< <template-parameter-1-1> >::allocate(std::size_t) [with _Tp = std::_Sp_counted_ptr_inplace<dbaui::OQueryTableConnectionData, std::allocator<void>, __gnu_cxx::_S_atomic>]’ at /usr/include/c++/16/bits/allocator.h:206:40,
>     inlined from ‘static constexpr _Tp* std::allocator_traits<std::allocator<_CharT> >::allocate(allocator_type&, size_type) [with _Tp = std::_Sp_counted_ptr_inplace<dbaui::OQueryTableConnectionData, std::allocator<void>, __gnu_cxx::_S_atomic>]’ at /usr/include/c++/16/bits/alloc_traits.h:638:28,
>     inlined from ‘std::__allocated_ptr<_Alloc> std::__allocate_guarded(_Alloc&) [with _Alloc = allocator<_Sp_counted_ptr_inplace<dbaui::OQueryTableConnectionData, allocator<void>, __gnu_cxx::_S_atomic> >]’ at /usr/include/c++/16/bits/allocated_ptr.h:103:69,
>     inlined from ‘std::__shared_count<_Lp>::__shared_count(_Tp*&, std::_Sp_alloc_shared_tag<_Alloc>, _Args&& ...) [with _Tp = dbaui::OQueryTableConnectionData; _Alloc = std::allocator<void>; _Args = {const std::shared_ptr<dbaui::OTableWindowData>&, const std::shared_ptr<dbaui::OTableWindowData>&}; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1034:9,
>     inlined from ‘std::__shared_ptr<_Tp, _Lp>::__shared_ptr(std::_Sp_alloc_shared_tag<_Tp>, _Args&& ...) [with _Alloc = std::allocator<void>; _Args = {const std::shared_ptr<dbaui::OTableWindowData>&, const std::shared_ptr<dbaui::OTableWindowData>&}; _Tp = dbaui::OQueryTableConnectionData; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1812:14,
>     inlined from ‘std::shared_ptr<_Tp>::shared_ptr(std::_Sp_alloc_shared_tag<_Tp>, _Args&& ...) [with _Alloc = std::allocator<void>; _Args = {const std::shared_ptr<dbaui::OTableWindowData>&, const std::shared_ptr<dbaui::OTableWindowData>&}; _Tp = dbaui::OQueryTableConnectionData]’ at /usr/include/c++/16/bits/shared_ptr.h:463:59,
>     inlined from ‘std::shared_ptr<std::_NonArray<_Tp> > std::make_shared(_Args&& ...) [with _Tp = dbaui::OQueryTableConnectionData; _Args = {const shared_ptr<dbaui::OTableWindowData>&, const shared_ptr<dbaui::OTableWindowData>&}]’ at /usr/include/c++/16/bits/shared_ptr.h:1066:39,
>     inlined from ‘virtual void dbaui::OQueryTableView::AddConnection(const dbaui::OJoinExchangeData&, const dbaui::OJoinExchangeData&)’ at engine/dbaccess/source/ui/querydesign/QueryTableView.cxx:539:121:
> /usr/include/c++/16/bits/new_allocator.h:162:75: note: at offset 16 into object of size 104 allocated by ‘operator new’
>   162 |           return static_cast<_Tp*>(_GLIBCXX_OPERATOR_NEW(__n * sizeof(_Tp)));
>       |                                                                           ^

> In file included from /usr/include/c++/16/bits/stl_tempbuf.h:61,
>                  from /usr/include/c++/16/memory:68,
>                  from engine/include/dbaccess/dataview.hxx:22,
>                  from engine/reportdesign/source/ui/inc/DesignView.hxx:22,
>                  from engine/reportdesign/source/ui/inc/ReportController.hxx:22,
>                  from engine/reportdesign/source/ui/report/ReportController.cxx:20:
> In function ‘constexpr void std::destroy_at(_Tp*) [with _Tp = rptui::OGroupsSortingDialog]’,
>     inlined from ‘constexpr void std::_Destroy(_Tp*) [with _Tp = rptui::OGroupsSortingDialog]’ at /usr/include/c++/16/bits/stl_construct.h:164:22,
>     inlined from ‘static constexpr void std::allocator_traits<std::allocator<void> >::destroy(allocator_type&, _Up*) [with _Up = rptui::OGroupsSortingDialog]’ at /usr/include/c++/16/bits/alloc_traits.h:859:17,
>     inlined from ‘void std::_Sp_counted_ptr_inplace<_Tp, _Alloc, _Lp>::_M_dispose() [with _Tp = rptui::OGroupsSortingDialog; _Alloc = std::allocator<void>; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:682:35,
>     inlined from ‘void std::_Sp_counted_base<_Lp>::_M_release() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:423:18,
>     inlined from ‘void std::_Sp_counted_base<_Lp>::_M_release() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:392:5,
>     inlined from ‘std::__shared_count<_Lp>::~__shared_count() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1136:21,
>     inlined from ‘std::__shared_ptr<_Tp, _Lp>::~__shared_ptr() [with _Tp = rptui::AnyConverter; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1610:7,
>     inlined from ‘std::shared_ptr<rptui::AnyConverter>::~shared_ptr()’ at /usr/include/c++/16/bits/shared_ptr.h:175:11,
>     inlined from ‘const com::sun::star::uno::Reference<com::sun::star::sdbc::XRowSet>& rptui::OReportController::getRowSet()’ at engine/reportdesign/source/ui/report/ReportController.cxx:2983:5:
> /usr/include/c++/16/bits/stl_construct.h:88:25: error: array subscript ‘rptui::OGroupsSortingDialog[0]’ is partly outside array bounds of ‘unsigned char [24]’ [-Werror=array-bounds=]
>    88 |         __location->~_Tp();
>       |         ~~~~~~~~~~~~~~~~^~
> In file included from /usr/include/c++/16/x86_64-redhat-linux/bits/c++allocator.h:33,
>                  from /usr/include/c++/16/bits/allocator.h:46,
>                  from /usr/include/c++/16/memory:67:
> In member function ‘constexpr _Tp* std::__new_allocator<_Tp>::allocate(size_type, const void*) [with _Tp = std::_Sp_counted_ptr_inplace<rptui::AnyConverter, std::allocator<void>, __gnu_cxx::_S_atomic>]’,
>     inlined from ‘constexpr _Tp* std::allocator< <template-parameter-1-1> >::allocate(std::size_t) [with _Tp = std::_Sp_counted_ptr_inplace<rptui::AnyConverter, std::allocator<void>, __gnu_cxx::_S_atomic>]’ at /usr/include/c++/16/bits/allocator.h:206:40,
>     inlined from ‘static constexpr _Tp* std::allocator_traits<std::allocator<_Up> >::allocate(allocator_type&, size_type) [with _Tp = std::_Sp_counted_ptr_inplace<rptui::AnyConverter, std::allocator<void>, __gnu_cxx::_S_atomic>]’ at /usr/include/c++/16/bits/alloc_traits.h:638:28,
>     inlined from ‘std::__allocated_ptr<_Alloc> std::__allocate_guarded(_Alloc&) [with _Alloc = allocator<_Sp_counted_ptr_inplace<rptui::AnyConverter, allocator<void>, __gnu_cxx::_S_atomic> >]’ at /usr/include/c++/16/bits/allocated_ptr.h:103:69,
>     inlined from ‘std::__shared_count<_Lp>::__shared_count(_Tp*&, std::_Sp_alloc_shared_tag<_Alloc>, _Args&& ...) [with _Tp = rptui::AnyConverter; _Alloc = std::allocator<void>; _Args = {}; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1034:9,
>     inlined from ‘std::__shared_ptr<_Tp, _Lp>::__shared_ptr(std::_Sp_alloc_shared_tag<_Tp>, _Args&& ...) [with _Alloc = std::allocator<void>; _Args = {}; _Tp = rptui::AnyConverter; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1812:14,
>     inlined from ‘std::shared_ptr<_Tp>::shared_ptr(std::_Sp_alloc_shared_tag<_Tp>, _Args&& ...) [with _Alloc = std::allocator<void>; _Args = {}; _Tp = rptui::AnyConverter]’ at /usr/include/c++/16/bits/shared_ptr.h:463:59,
>     inlined from ‘std::shared_ptr<std::_NonArray<_Tp> > std::make_shared(_Args&& ...) [with _Tp = rptui::AnyConverter; _Args = {}]’ at /usr/include/c++/16/bits/shared_ptr.h:1066:39,
>     inlined from ‘const com::sun::star::uno::Reference<com::sun::star::sdbc::XRowSet>& rptui::OReportController::getRowSet()’ at engine/reportdesign/source/ui/report/ReportController.cxx:2974:60:
> /usr/include/c++/16/bits/new_allocator.h:162:75: note: at offset 16 into object of size 24 allocated by ‘operator new’
>   162 |           return static_cast<_Tp*>(_GLIBCXX_OPERATOR_NEW(__n * sizeof(_Tp)));
>       |                                                                           ^

> In file included from /usr/include/c++/16/bits/unordered_map.h:33,
>                  from /usr/include/c++/16/unordered_map:43,
>                  from /usr/include/c++/16/functional:80,
>                  from engine/include/rtl/ref.hxx:27,
>                  from engine/include/vcl/vclptr.hxx:26,
>                  from engine/sc/inc/document.hxx:25,
>                  from engine/sc/source/core/data/document10.cxx:11:
> In destructor ‘std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::~_Hashtable() [with _Key = short int; _Value = std::pair<const short int, std::unordered_map<short int, sc::ColumnBlockPosition> >; _Alloc = std::allocator<std::pair<const short int, std::unordered_map<short int, sc::ColumnBlockPosition> > >; _ExtractKey = std::__detail::_Select1st; _Equal = std::equal_to<short int>; _Hash = std::hash<short int>; _RangeHash = std::__detail::_Mod_range_hashing; _Unused = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<false, false, true>]’,
>     inlined from ‘std::unordered_map<short int, std::unordered_map<short int, sc::ColumnBlockPosition> >::~unordered_map()’ at /usr/include/c++/16/bits/unordered_map.h:112:11,
>     inlined from ‘sc::ColumnBlockPositionSet::~ColumnBlockPositionSet()’ at engine/sc/inc/mtvelements.hxx:179:7,
>     inlined from ‘constexpr void std::destroy_at(_Tp*) [with _Tp = sc::ColumnBlockPositionSet]’ at /usr/include/c++/16/bits/stl_construct.h:88:18,
>     inlined from ‘constexpr void std::_Destroy(_Tp*) [with _Tp = sc::ColumnBlockPositionSet]’ at /usr/include/c++/16/bits/stl_construct.h:164:22,
>     inlined from ‘static constexpr void std::allocator_traits<std::allocator<void> >::destroy(allocator_type&, _Up*) [with _Up = sc::ColumnBlockPositionSet]’ at /usr/include/c++/16/bits/alloc_traits.h:859:17,
>     inlined from ‘void std::_Sp_counted_ptr_inplace<_Tp, _Alloc, _Lp>::_M_dispose() [with _Tp = sc::ColumnBlockPositionSet; _Alloc = std::allocator<void>; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:682:35,
>     inlined from ‘void std::_Sp_counted_base<_Lp>::_M_release() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:423:18,
>     inlined from ‘void std::_Sp_counted_base<_Lp>::_M_release() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:392:5,
>     inlined from ‘std::__shared_count<_Lp>::~__shared_count() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1136:21,
>     inlined from ‘std::__shared_ptr<_Tp, _Lp>::~__shared_ptr() [with _Tp = sc::StartListeningContext; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1610:7,
>     inlined from ‘std::shared_ptr<sc::StartListeningContext>::~shared_ptr()’ at /usr/include/c++/16/bits/shared_ptr.h:175:11,
>     inlined from ‘{anonymous}::StartNeededListenersHandler::~StartNeededListenersHandler()’ at engine/sc/source/core/data/document10.cxx:552:7,
>     inlined from ‘void ScDocument::StartNeededListeners()’ at engine/sc/source/core/data/document10.cxx:574:18:
> /usr/include/c++/16/bits/hashtable.h:1904:5: error: array subscript ‘std::_Hashtable<short int, std::pair<const short int, std::unordered_map<short int, sc::ColumnBlockPosition> >, std::allocator<std::pair<const short int, std::unordered_map<short int, sc::ColumnBlockPosition> > >, std::__detail::_Select1st, std::equal_to<short int>, std::hash<short int>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<false, false, true> >[0]’ is partly outside array bounds of ‘unsigned char [56]’ [-Werror=array-bounds=]
>  1904 |     }
>       |     ^
> In file included from /usr/include/c++/16/x86_64-redhat-linux/bits/c++allocator.h:33,
>                  from /usr/include/c++/16/bits/allocator.h:46,
>                  from /usr/include/c++/16/memory:67,
>                  from engine/sc/source/core/data/document10.cxx:10:
> In member function ‘constexpr _Tp* std::__new_allocator<_Tp>::allocate(size_type, const void*) [with _Tp = std::_Sp_counted_ptr_inplace<sc::StartListeningContext, std::allocator<void>, __gnu_cxx::_S_atomic>]’,
>     inlined from ‘constexpr _Tp* std::allocator< <template-parameter-1-1> >::allocate(std::size_t) [with _Tp = std::_Sp_counted_ptr_inplace<sc::StartListeningContext, std::allocator<void>, __gnu_cxx::_S_atomic>]’ at /usr/include/c++/16/bits/allocator.h:206:40,
>     inlined from ‘static constexpr _Tp* std::allocator_traits<std::allocator<_Up> >::allocate(allocator_type&, size_type) [with _Tp = std::_Sp_counted_ptr_inplace<sc::StartListeningContext, std::allocator<void>, __gnu_cxx::_S_atomic>]’ at /usr/include/c++/16/bits/alloc_traits.h:638:28,
>     inlined from ‘std::__allocated_ptr<_Alloc> std::__allocate_guarded(_Alloc&) [with _Alloc = allocator<_Sp_counted_ptr_inplace<sc::StartListeningContext, allocator<void>, __gnu_cxx::_S_atomic> >]’ at /usr/include/c++/16/bits/allocated_ptr.h:103:69,
>     inlined from ‘std::__shared_count<_Lp>::__shared_count(_Tp*&, std::_Sp_alloc_shared_tag<_Alloc>, _Args&& ...) [with _Tp = sc::StartListeningContext; _Alloc = std::allocator<void>; _Args = {ScDocument&}; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1034:9,
>     inlined from ‘std::__shared_ptr<_Tp, _Lp>::__shared_ptr(std::_Sp_alloc_shared_tag<_Tp>, _Args&& ...) [with _Alloc = std::allocator<void>; _Args = {ScDocument&}; _Tp = sc::StartListeningContext; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1812:14,
>     inlined from ‘std::shared_ptr<_Tp>::shared_ptr(std::_Sp_alloc_shared_tag<_Tp>, _Args&& ...) [with _Alloc = std::allocator<void>; _Args = {ScDocument&}; _Tp = sc::StartListeningContext]’ at /usr/include/c++/16/bits/shared_ptr.h:463:59,
>     inlined from ‘std::shared_ptr<std::_NonArray<_Tp> > std::make_shared(_Args&& ...) [with _Tp = sc::StartListeningContext; _Args = {ScDocument&}]’ at /usr/include/c++/16/bits/shared_ptr.h:1066:39,
>     inlined from ‘{anonymous}::StartNeededListenersHandler::StartNeededListenersHandler(ScDocument&)’ at engine/sc/source/core/data/document10.cxx:556:64,
>     inlined from ‘void ScDocument::StartNeededListeners()’ at engine/sc/source/core/data/document10.cxx:574:82:
> /usr/include/c++/16/bits/new_allocator.h:162:75: note: at offset 24 into object of size 56 allocated by ‘operator new’
>   162 |           return static_cast<_Tp*>(_GLIBCXX_OPERATOR_NEW(__n * sizeof(_Tp)));
>       |                                                                           ^
> In file included from engine/sc/inc/column.hxx:28,
>                  from engine/sc/inc/table.hxx:25,
>                  from engine/sc/source/core/data/document10.cxx:14:
> In destructor ‘sc::ColumnBlockPositionSet::~ColumnBlockPositionSet()’,
>     inlined from ‘constexpr void std::destroy_at(_Tp*) [with _Tp = sc::ColumnBlockPositionSet]’ at /usr/include/c++/16/bits/stl_construct.h:88:18,
>     inlined from ‘constexpr void std::_Destroy(_Tp*) [with _Tp = sc::ColumnBlockPositionSet]’ at /usr/include/c++/16/bits/stl_construct.h:164:22,
>     inlined from ‘static constexpr void std::allocator_traits<std::allocator<void> >::destroy(allocator_type&, _Up*) [with _Up = sc::ColumnBlockPositionSet]’ at /usr/include/c++/16/bits/alloc_traits.h:859:17,
>     inlined from ‘void std::_Sp_counted_ptr_inplace<_Tp, _Alloc, _Lp>::_M_dispose() [with _Tp = sc::ColumnBlockPositionSet; _Alloc = std::allocator<void>; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:682:35,
>     inlined from ‘void std::_Sp_counted_base<_Lp>::_M_release() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:423:18,
>     inlined from ‘void std::_Sp_counted_base<_Lp>::_M_release() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:392:5,
>     inlined from ‘std::__shared_count<_Lp>::~__shared_count() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1136:21,
>     inlined from ‘std::__shared_ptr<_Tp, _Lp>::~__shared_ptr() [with _Tp = sc::StartListeningContext; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1610:7,
>     inlined from ‘std::shared_ptr<sc::StartListeningContext>::~shared_ptr()’ at /usr/include/c++/16/bits/shared_ptr.h:175:11,
>     inlined from ‘{anonymous}::StartNeededListenersHandler::~StartNeededListenersHandler()’ at engine/sc/source/core/data/document10.cxx:552:7,
>     inlined from ‘void ScDocument::StartNeededListeners()’ at engine/sc/source/core/data/document10.cxx:574:18:
> engine/sc/inc/mtvelements.hxx:179:7: error: array subscript ‘sc::ColumnBlockPositionSet[0]’ is partly outside array bounds of ‘unsigned char [56]’ [-Werror=array-bounds=]
>   179 | class ColumnBlockPositionSet
>       |       ^~~~~~~~~~~~~~~~~~~~~~
> In member function ‘constexpr _Tp* std::__new_allocator<_Tp>::allocate(size_type, const void*) [with _Tp = std::_Sp_counted_ptr_inplace<sc::StartListeningContext, std::allocator<void>, __gnu_cxx::_S_atomic>]’,
>     inlined from ‘constexpr _Tp* std::allocator< <template-parameter-1-1> >::allocate(std::size_t) [with _Tp = std::_Sp_counted_ptr_inplace<sc::StartListeningContext, std::allocator<void>, __gnu_cxx::_S_atomic>]’ at /usr/include/c++/16/bits/allocator.h:206:40,
>     inlined from ‘static constexpr _Tp* std::allocator_traits<std::allocator<_Up> >::allocate(allocator_type&, size_type) [with _Tp = std::_Sp_counted_ptr_inplace<sc::StartListeningContext, std::allocator<void>, __gnu_cxx::_S_atomic>]’ at /usr/include/c++/16/bits/alloc_traits.h:638:28,
>     inlined from ‘std::__allocated_ptr<_Alloc> std::__allocate_guarded(_Alloc&) [with _Alloc = allocator<_Sp_counted_ptr_inplace<sc::StartListeningContext, allocator<void>, __gnu_cxx::_S_atomic> >]’ at /usr/include/c++/16/bits/allocated_ptr.h:103:69,
>     inlined from ‘std::__shared_count<_Lp>::__shared_count(_Tp*&, std::_Sp_alloc_shared_tag<_Alloc>, _Args&& ...) [with _Tp = sc::StartListeningContext; _Alloc = std::allocator<void>; _Args = {ScDocument&}; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1034:9,
>     inlined from ‘std::__shared_ptr<_Tp, _Lp>::__shared_ptr(std::_Sp_alloc_shared_tag<_Tp>, _Args&& ...) [with _Alloc = std::allocator<void>; _Args = {ScDocument&}; _Tp = sc::StartListeningContext; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1812:14,
>     inlined from ‘std::shared_ptr<_Tp>::shared_ptr(std::_Sp_alloc_shared_tag<_Tp>, _Args&& ...) [with _Alloc = std::allocator<void>; _Args = {ScDocument&}; _Tp = sc::StartListeningContext]’ at /usr/include/c++/16/bits/shared_ptr.h:463:59,
>     inlined from ‘std::shared_ptr<std::_NonArray<_Tp> > std::make_shared(_Args&& ...) [with _Tp = sc::StartListeningContext; _Args = {ScDocument&}]’ at /usr/include/c++/16/bits/shared_ptr.h:1066:39,
>     inlined from ‘{anonymous}::StartNeededListenersHandler::StartNeededListenersHandler(ScDocument&)’ at engine/sc/source/core/data/document10.cxx:556:64,
>     inlined from ‘void ScDocument::StartNeededListeners()’ at engine/sc/source/core/data/document10.cxx:574:82:
> /usr/include/c++/16/bits/new_allocator.h:162:75: note: at offset 16 into object of size 56 allocated by ‘operator new’
>   162 |           return static_cast<_Tp*>(_GLIBCXX_OPERATOR_NEW(__n * sizeof(_Tp)));
>       |                                                                           ^
> In destructor ‘std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::~_Hashtable() [with _Key = short int; _Value = std::pair<const short int, std::unordered_map<short int, sc::ColumnBlockPosition> >; _Alloc = std::allocator<std::pair<const short int, std::unordered_map<short int, sc::ColumnBlockPosition> > >; _ExtractKey = std::__detail::_Select1st; _Equal = std::equal_to<short int>; _Hash = std::hash<short int>; _RangeHash = std::__detail::_Mod_range_hashing; _Unused = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<false, false, true>]’,
>     inlined from ‘std::unordered_map<short int, std::unordered_map<short int, sc::ColumnBlockPosition> >::~unordered_map()’ at /usr/include/c++/16/bits/unordered_map.h:112:11,
>     inlined from ‘sc::ColumnBlockPositionSet::~ColumnBlockPositionSet()’ at engine/sc/inc/mtvelements.hxx:179:7,
>     inlined from ‘constexpr void std::destroy_at(_Tp*) [with _Tp = sc::ColumnBlockPositionSet]’ at /usr/include/c++/16/bits/stl_construct.h:88:18,
>     inlined from ‘constexpr void std::_Destroy(_Tp*) [with _Tp = sc::ColumnBlockPositionSet]’ at /usr/include/c++/16/bits/stl_construct.h:164:22,
>     inlined from ‘static constexpr void std::allocator_traits<std::allocator<void> >::destroy(allocator_type&, _Up*) [with _Up = sc::ColumnBlockPositionSet]’ at /usr/include/c++/16/bits/alloc_traits.h:859:17,
>     inlined from ‘void std::_Sp_counted_ptr_inplace<_Tp, _Alloc, _Lp>::_M_dispose() [with _Tp = sc::ColumnBlockPositionSet; _Alloc = std::allocator<void>; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:682:35,
>     inlined from ‘void std::_Sp_counted_base<_Lp>::_M_release() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:423:18,
>     inlined from ‘void std::_Sp_counted_base<_Lp>::_M_release() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:392:5,
>     inlined from ‘std::__shared_count<_Lp>::~__shared_count() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1136:21,
>     inlined from ‘std::__shared_ptr<_Tp, _Lp>::~__shared_ptr() [with _Tp = sc::StartListeningContext; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1610:7,
>     inlined from ‘std::shared_ptr<sc::StartListeningContext>::~shared_ptr()’ at /usr/include/c++/16/bits/shared_ptr.h:175:11,
>     inlined from ‘{anonymous}::StartNeededListenersHandler::~StartNeededListenersHandler()’ at engine/sc/source/core/data/document10.cxx:552:7,
>     inlined from ‘void ScDocument::StartNeededListeners(const std::shared_ptr<const sc::ColumnSet>&)’ at engine/sc/source/core/data/document10.cxx:579:18:
> /usr/include/c++/16/bits/hashtable.h:1904:5: error: array subscript ‘std::_Hashtable<short int, std::pair<const short int, std::unordered_map<short int, sc::ColumnBlockPosition> >, std::allocator<std::pair<const short int, std::unordered_map<short int, sc::ColumnBlockPosition> > >, std::__detail::_Select1st, std::equal_to<short int>, std::hash<short int>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<false, false, true> >[0]’ is partly outside array bounds of ‘unsigned char [56]’ [-Werror=array-bounds=]
>  1904 |     }
>       |     ^
> In member function ‘constexpr _Tp* std::__new_allocator<_Tp>::allocate(size_type, const void*) [with _Tp = std::_Sp_counted_ptr_inplace<sc::StartListeningContext, std::allocator<void>, __gnu_cxx::_S_atomic>]’,
>     inlined from ‘constexpr _Tp* std::allocator< <template-parameter-1-1> >::allocate(std::size_t) [with _Tp = std::_Sp_counted_ptr_inplace<sc::StartListeningContext, std::allocator<void>, __gnu_cxx::_S_atomic>]’ at /usr/include/c++/16/bits/allocator.h:206:40,
>     inlined from ‘static constexpr _Tp* std::allocator_traits<std::allocator<_Up> >::allocate(allocator_type&, size_type) [with _Tp = std::_Sp_counted_ptr_inplace<sc::StartListeningContext, std::allocator<void>, __gnu_cxx::_S_atomic>]’ at /usr/include/c++/16/bits/alloc_traits.h:638:28,
>     inlined from ‘std::__allocated_ptr<_Alloc> std::__allocate_guarded(_Alloc&) [with _Alloc = allocator<_Sp_counted_ptr_inplace<sc::StartListeningContext, allocator<void>, __gnu_cxx::_S_atomic> >]’ at /usr/include/c++/16/bits/allocated_ptr.h:103:69,
>     inlined from ‘std::__shared_count<_Lp>::__shared_count(_Tp*&, std::_Sp_alloc_shared_tag<_Alloc>, _Args&& ...) [with _Tp = sc::StartListeningContext; _Alloc = std::allocator<void>; _Args = {ScDocument&}; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1034:9,
>     inlined from ‘std::__shared_ptr<_Tp, _Lp>::__shared_ptr(std::_Sp_alloc_shared_tag<_Tp>, _Args&& ...) [with _Alloc = std::allocator<void>; _Args = {ScDocument&}; _Tp = sc::StartListeningContext; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1812:14,
>     inlined from ‘std::shared_ptr<_Tp>::shared_ptr(std::_Sp_alloc_shared_tag<_Tp>, _Args&& ...) [with _Alloc = std::allocator<void>; _Args = {ScDocument&}; _Tp = sc::StartListeningContext]’ at /usr/include/c++/16/bits/shared_ptr.h:463:59,
>     inlined from ‘std::shared_ptr<std::_NonArray<_Tp> > std::make_shared(_Args&& ...) [with _Tp = sc::StartListeningContext; _Args = {ScDocument&}]’ at /usr/include/c++/16/bits/shared_ptr.h:1066:39,
>     inlined from ‘{anonymous}::StartNeededListenersHandler::StartNeededListenersHandler(ScDocument&, const std::shared_ptr<const sc::ColumnSet>&)’ at engine/sc/source/core/data/document10.cxx:558:9,
>     inlined from ‘void ScDocument::StartNeededListeners(const std::shared_ptr<const sc::ColumnSet>&)’ at engine/sc/source/core/data/document10.cxx:579:92:
> /usr/include/c++/16/bits/new_allocator.h:162:75: note: at offset 24 into object of size 56 allocated by ‘operator new’
>   162 |           return static_cast<_Tp*>(_GLIBCXX_OPERATOR_NEW(__n * sizeof(_Tp)));
>       |                                                                           ^
> In destructor ‘sc::ColumnBlockPositionSet::~ColumnBlockPositionSet()’,
>     inlined from ‘constexpr void std::destroy_at(_Tp*) [with _Tp = sc::ColumnBlockPositionSet]’ at /usr/include/c++/16/bits/stl_construct.h:88:18,
>     inlined from ‘constexpr void std::_Destroy(_Tp*) [with _Tp = sc::ColumnBlockPositionSet]’ at /usr/include/c++/16/bits/stl_construct.h:164:22,
>     inlined from ‘static constexpr void std::allocator_traits<std::allocator<void> >::destroy(allocator_type&, _Up*) [with _Up = sc::ColumnBlockPositionSet]’ at /usr/include/c++/16/bits/alloc_traits.h:859:17,
>     inlined from ‘void std::_Sp_counted_ptr_inplace<_Tp, _Alloc, _Lp>::_M_dispose() [with _Tp = sc::ColumnBlockPositionSet; _Alloc = std::allocator<void>; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:682:35,
>     inlined from ‘void std::_Sp_counted_base<_Lp>::_M_release() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:423:18,
>     inlined from ‘void std::_Sp_counted_base<_Lp>::_M_release() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:392:5,
>     inlined from ‘std::__shared_count<_Lp>::~__shared_count() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1136:21,
>     inlined from ‘std::__shared_ptr<_Tp, _Lp>::~__shared_ptr() [with _Tp = sc::StartListeningContext; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1610:7,
>     inlined from ‘std::shared_ptr<sc::StartListeningContext>::~shared_ptr()’ at /usr/include/c++/16/bits/shared_ptr.h:175:11,
>     inlined from ‘{anonymous}::StartNeededListenersHandler::~StartNeededListenersHandler()’ at engine/sc/source/core/data/document10.cxx:552:7,
>     inlined from ‘void ScDocument::StartNeededListeners(const std::shared_ptr<const sc::ColumnSet>&)’ at engine/sc/source/core/data/document10.cxx:579:18:
> engine/sc/inc/mtvelements.hxx:179:7: error: array subscript ‘sc::ColumnBlockPositionSet[0]’ is partly outside array bounds of ‘unsigned char [56]’ [-Werror=array-bounds=]
>   179 | class ColumnBlockPositionSet
>       |       ^~~~~~~~~~~~~~~~~~~~~~
> In member function ‘constexpr _Tp* std::__new_allocator<_Tp>::allocate(size_type, const void*) [with _Tp = std::_Sp_counted_ptr_inplace<sc::StartListeningContext, std::allocator<void>, __gnu_cxx::_S_atomic>]’,
>     inlined from ‘constexpr _Tp* std::allocator< <template-parameter-1-1> >::allocate(std::size_t) [with _Tp = std::_Sp_counted_ptr_inplace<sc::StartListeningContext, std::allocator<void>, __gnu_cxx::_S_atomic>]’ at /usr/include/c++/16/bits/allocator.h:206:40,
>     inlined from ‘static constexpr _Tp* std::allocator_traits<std::allocator<_Up> >::allocate(allocator_type&, size_type) [with _Tp = std::_Sp_counted_ptr_inplace<sc::StartListeningContext, std::allocator<void>, __gnu_cxx::_S_atomic>]’ at /usr/include/c++/16/bits/alloc_traits.h:638:28,
>     inlined from ‘std::__allocated_ptr<_Alloc> std::__allocate_guarded(_Alloc&) [with _Alloc = allocator<_Sp_counted_ptr_inplace<sc::StartListeningContext, allocator<void>, __gnu_cxx::_S_atomic> >]’ at /usr/include/c++/16/bits/allocated_ptr.h:103:69,
>     inlined from ‘std::__shared_count<_Lp>::__shared_count(_Tp*&, std::_Sp_alloc_shared_tag<_Alloc>, _Args&& ...) [with _Tp = sc::StartListeningContext; _Alloc = std::allocator<void>; _Args = {ScDocument&}; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1034:9,
>     inlined from ‘std::__shared_ptr<_Tp, _Lp>::__shared_ptr(std::_Sp_alloc_shared_tag<_Tp>, _Args&& ...) [with _Alloc = std::allocator<void>; _Args = {ScDocument&}; _Tp = sc::StartListeningContext; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1812:14,
>     inlined from ‘std::shared_ptr<_Tp>::shared_ptr(std::_Sp_alloc_shared_tag<_Tp>, _Args&& ...) [with _Alloc = std::allocator<void>; _Args = {ScDocument&}; _Tp = sc::StartListeningContext]’ at /usr/include/c++/16/bits/shared_ptr.h:463:59,
>     inlined from ‘std::shared_ptr<std::_NonArray<_Tp> > std::make_shared(_Args&& ...) [with _Tp = sc::StartListeningContext; _Args = {ScDocument&}]’ at /usr/include/c++/16/bits/shared_ptr.h:1066:39,
>     inlined from ‘{anonymous}::StartNeededListenersHandler::StartNeededListenersHandler(ScDocument&, const std::shared_ptr<const sc::ColumnSet>&)’ at engine/sc/source/core/data/document10.cxx:558:9,
>     inlined from ‘void ScDocument::StartNeededListeners(const std::shared_ptr<const sc::ColumnSet>&)’ at engine/sc/source/core/data/document10.cxx:579:92:
> /usr/include/c++/16/bits/new_allocator.h:162:75: note: at offset 16 into object of size 56 allocated by ‘operator new’
>   162 |           return static_cast<_Tp*>(_GLIBCXX_OPERATOR_NEW(__n * sizeof(_Tp)));
>       |                                                                           ^

> In file included from engine/include/vcl/weld.hxx:13,
>                  from engine/include/sfx2/basedlgs.hxx:25,
>                  from engine/sw/source/uibase/inc/contentcontroldlg.hxx:21,
>                  from engine/sw/source/ui/misc/contentcontroldlg.cxx:20:
> In destructor ‘constexpr rtl::OUString::~OUString()’,
>     inlined from ‘constexpr SwContentControlListItem::~SwContentControlListItem()’ at engine/sw/inc/formatcontentcontrol.hxx:90:20,
>     inlined from ‘constexpr void std::destroy_at(_Tp*) [with _Tp = SwContentControlListItem]’ at /usr/include/c++/16/bits/stl_construct.h:88:18,
>     inlined from ‘constexpr void std::_Destroy(_Tp*) [with _Tp = SwContentControlListItem]’ at /usr/include/c++/16/bits/stl_construct.h:164:22,
>     inlined from ‘static constexpr void std::allocator_traits<std::allocator<void> >::destroy(allocator_type&, _Up*) [with _Up = SwContentControlListItem]’ at /usr/include/c++/16/bits/alloc_traits.h:859:17,
>     inlined from ‘void std::_Sp_counted_ptr_inplace<_Tp, _Alloc, _Lp>::_M_dispose() [with _Tp = SwContentControlListItem; _Alloc = std::allocator<void>; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:682:35,
>     inlined from ‘void std::_Sp_counted_base<_Lp>::_M_release() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:423:18,
>     inlined from ‘void std::_Sp_counted_base<_Lp>::_M_release() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:392:5,
>     inlined from ‘std::__shared_count<_Lp>::~__shared_count() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1136:21,
>     inlined from ‘std::__shared_ptr<_Tp, _Lp>::~__shared_ptr() [with _Tp = SvxCharacterMap; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1610:7,
>     inlined from ‘std::shared_ptr<SvxCharacterMap>::~shared_ptr()’ at /usr/include/c++/16/bits/shared_ptr.h:175:11,
>     inlined from ‘void SwContentControlDlg::SelectCharHdl(weld::Button&)’ at engine/sw/source/ui/misc/contentcontroldlg.cxx:332:1:
> engine/include/rtl/ustring.hxx:540:32: error: array subscript 3 is outside array bounds of ‘void [24]’ [-Werror=array-bounds=]
>   540 |             rtl_uString_release( pData );
>       |             ~~~~~~~~~~~~~~~~~~~^~~~~~~~~
> In file included from /usr/include/c++/16/bits/shared_ptr.h:53,
>                  from /usr/include/c++/16/memory:82,
>                  from engine/include/sfx2/basedlgs.hxx:22:
> In constructor ‘std::__shared_count<_Lp>::__shared_count(_Ptr) [with _Ptr = SvxCharacterMap*; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’,
>     inlined from ‘std::__shared_count<_Lp>::__shared_count(_Ptr, std::false_type) [with _Ptr = SvxCharacterMap*; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:992:22,
>     inlined from ‘std::__shared_ptr<_Tp, _Lp>::__shared_ptr(_Yp*) [with _Yp = SvxCharacterMap; <template-parameter-2-2> = void; _Tp = SvxCharacterMap; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1555:17,
>     inlined from ‘std::shared_ptr<_Tp>::shared_ptr(_Yp*) [with _Yp = SvxCharacterMap; <template-parameter-2-2> = void; _Tp = SvxCharacterMap]’ at /usr/include/c++/16/bits/shared_ptr.h:213:46,
>     inlined from ‘void SwContentControlDlg::SelectCharHdl(weld::Button&)’ at engine/sw/source/ui/misc/contentcontroldlg.cxx:305:97:
> /usr/include/c++/16/bits/shared_ptr_base.h:981:23: note: at offset 24 into object of size 24 allocated by ‘operator new’
>   981 |               _M_pi = new _Sp_counted_ptr<_Ptr, _Lp>(__p);
>       |                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> In destructor ‘constexpr rtl::OUString::~OUString()’,
>     inlined from ‘constexpr SwContentControlListItem::~SwContentControlListItem()’ at engine/sw/inc/formatcontentcontrol.hxx:90:20,
>     inlined from ‘constexpr void std::destroy_at(_Tp*) [with _Tp = SwContentControlListItem]’ at /usr/include/c++/16/bits/stl_construct.h:88:18,
>     inlined from ‘constexpr void std::_Destroy(_Tp*) [with _Tp = SwContentControlListItem]’ at /usr/include/c++/16/bits/stl_construct.h:164:22,
>     inlined from ‘static constexpr void std::allocator_traits<std::allocator<void> >::destroy(allocator_type&, _Up*) [with _Up = SwContentControlListItem]’ at /usr/include/c++/16/bits/alloc_traits.h:859:17,
>     inlined from ‘void std::_Sp_counted_ptr_inplace<_Tp, _Alloc, _Lp>::_M_dispose() [with _Tp = SwContentControlListItem; _Alloc = std::allocator<void>; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:682:35,
>     inlined from ‘void std::_Sp_counted_base<_Lp>::_M_release() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:423:18,
>     inlined from ‘void std::_Sp_counted_base<_Lp>::_M_release() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:392:5,
>     inlined from ‘std::__shared_count<_Lp>::~__shared_count() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1136:21,
>     inlined from ‘std::__shared_ptr<_Tp, _Lp>::~__shared_ptr() [with _Tp = SvxCharacterMap; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1610:7,
>     inlined from ‘std::shared_ptr<SvxCharacterMap>::~shared_ptr()’ at /usr/include/c++/16/bits/shared_ptr.h:175:11,
>     inlined from ‘void SwContentControlDlg::SelectCharHdl(weld::Button&)’ at engine/sw/source/ui/misc/contentcontroldlg.cxx:332:1:
> engine/include/rtl/ustring.hxx:541:5: error: array subscript 3 is outside array bounds of ‘void [24]’ [-Werror=array-bounds=]
>   541 |     }
>       |     ^
> In constructor ‘std::__shared_count<_Lp>::__shared_count(_Ptr) [with _Ptr = SvxCharacterMap*; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’,
>     inlined from ‘std::__shared_count<_Lp>::__shared_count(_Ptr, std::false_type) [with _Ptr = SvxCharacterMap*; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:992:22,
>     inlined from ‘std::__shared_ptr<_Tp, _Lp>::__shared_ptr(_Yp*) [with _Yp = SvxCharacterMap; <template-parameter-2-2> = void; _Tp = SvxCharacterMap; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1555:17,
>     inlined from ‘std::shared_ptr<_Tp>::shared_ptr(_Yp*) [with _Yp = SvxCharacterMap; <template-parameter-2-2> = void; _Tp = SvxCharacterMap]’ at /usr/include/c++/16/bits/shared_ptr.h:213:46,
>     inlined from ‘void SwContentControlDlg::SelectCharHdl(weld::Button&)’ at engine/sw/source/ui/misc/contentcontroldlg.cxx:305:97:
> /usr/include/c++/16/bits/shared_ptr_base.h:981:23: note: at offset 24 into object of size 24 allocated by ‘operator new’
>   981 |               _M_pi = new _Sp_counted_ptr<_Ptr, _Lp>(__p);
>       |                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> In file included from engine/sw/inc/txatbase.hxx:32,
>                  from engine/sw/inc/textcontentcontrol.hxx:21,
>                  from engine/sw/source/ui/misc/contentcontroldlg.cxx:29:
> In destructor ‘constexpr SwContentControlListItem::~SwContentControlListItem()’,
>     inlined from ‘constexpr void std::destroy_at(_Tp*) [with _Tp = SwContentControlListItem]’ at /usr/include/c++/16/bits/stl_construct.h:88:18,
>     inlined from ‘constexpr void std::_Destroy(_Tp*) [with _Tp = SwContentControlListItem]’ at /usr/include/c++/16/bits/stl_construct.h:164:22,
>     inlined from ‘static constexpr void std::allocator_traits<std::allocator<void> >::destroy(allocator_type&, _Up*) [with _Up = SwContentControlListItem]’ at /usr/include/c++/16/bits/alloc_traits.h:859:17,
>     inlined from ‘void std::_Sp_counted_ptr_inplace<_Tp, _Alloc, _Lp>::_M_dispose() [with _Tp = SwContentControlListItem; _Alloc = std::allocator<void>; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:682:35,
>     inlined from ‘void std::_Sp_counted_base<_Lp>::_M_release() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:423:18,
>     inlined from ‘void std::_Sp_counted_base<_Lp>::_M_release() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:392:5,
>     inlined from ‘std::__shared_count<_Lp>::~__shared_count() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1136:21,
>     inlined from ‘std::__shared_ptr<_Tp, _Lp>::~__shared_ptr() [with _Tp = SvxCharacterMap; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1610:7,
>     inlined from ‘std::shared_ptr<SvxCharacterMap>::~shared_ptr()’ at /usr/include/c++/16/bits/shared_ptr.h:175:11,
>     inlined from ‘void SwContentControlDlg::SelectCharHdl(weld::Button&)’ at engine/sw/source/ui/misc/contentcontroldlg.cxx:332:1:
> engine/sw/inc/formatcontentcontrol.hxx:90:20: error: array subscript ‘SwContentControlListItem[1]’ is partly outside array bounds of ‘unsigned char [24]’ [-Werror=array-bounds=]
>    90 | class SW_DLLPUBLIC SwContentControlListItem
>       |                    ^~~~~~~~~~~~~~~~~~~~~~~~
> In constructor ‘std::__shared_count<_Lp>::__shared_count(_Ptr) [with _Ptr = SvxCharacterMap*; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’,
>     inlined from ‘std::__shared_count<_Lp>::__shared_count(_Ptr, std::false_type) [with _Ptr = SvxCharacterMap*; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:992:22,
>     inlined from ‘std::__shared_ptr<_Tp, _Lp>::__shared_ptr(_Yp*) [with _Yp = SvxCharacterMap; <template-parameter-2-2> = void; _Tp = SvxCharacterMap; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1555:17,
>     inlined from ‘std::shared_ptr<_Tp>::shared_ptr(_Yp*) [with _Yp = SvxCharacterMap; <template-parameter-2-2> = void; _Tp = SvxCharacterMap]’ at /usr/include/c++/16/bits/shared_ptr.h:213:46,
>     inlined from ‘void SwContentControlDlg::SelectCharHdl(weld::Button&)’ at engine/sw/source/ui/misc/contentcontroldlg.cxx:305:97:
> /usr/include/c++/16/bits/shared_ptr_base.h:981:23: note: at offset 16 into object of size 24 allocated by ‘operator new’
>   981 |               _M_pi = new _Sp_counted_ptr<_Ptr, _Lp>(__p);
>       |                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Signed-off-by: Stephan Bergmann <stephan.bergmann@collabora.com>
Change-Id: I59db4d41d745ac2bab8b0712fb2145a333fe5f42
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/1155
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
Reviewed-by: Michael Stahl <michael.stahl@collabora.com>
(cherry picked from commit 3e690ff02e2de8aeb052bf5a2d1f302134b907b1)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207168
Tested-by: Xisco Fauli <xiscofauli@libreoffice.org>
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
2026-06-23 12:27:17 +02:00
Balazs Varga b3fe433d9e sc: do not fabricate a table for a partial structured-reference paste
adjustDBRange() re-points a copied structured-reference token at the
matching table in the destination. When it found none it cloned the
source ScDBData keeping the *source* coordinates. Since the preceding
change recreates a fully-copied table at the paste position in
CopyDBsFromClip() before the cells are copied, reaching adjustDBRange()
with no match now means the copy covered only part of the table. Cloning
there registered a misplaced, header-less table whose column names
resolved only from a cached header (and broke on reload), with a total
that computed a value merely by coincidence.

Skip the fabrication for a clipboard paste and leave the reference
unresolved instead (index 0, i.e. #REF!). Gating on rOldDoc.IsClipboard()
keeps every other formula clone - undo/redo restore, transpose - on the
original create-the-table behaviour, so those paths still resolve. A
same-document paste is unaffected (the existing table is found by name)
and a full cross-document copy is unaffected because CopyDBsFromClip()
already recreated the table. Like the OOXML format, a partial copy now
creates no table. Matching that format's behaviour of keeping the
reference bound to the original table (a cross-document external
reference) would need external structured-reference support and is left
as future work.

Signed-off-by: Balazs Varga <balazs.varga@collabora.com>
Change-Id: I6e3b56770f3bd0c1f337f09abc914e0a58128ce0
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/4647
Reviewed-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
Tested-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
(cherry picked from commit 168b192f751b3dbb49e5212961f827df024327ef)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207001
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
2026-06-19 16:09:39 +02:00
Balazs Varga 3109313b04 sc: re-anchor a copied named table to the paste location
Commit 2b3f8ab2f66aa6f46a3bed0e26659006abf90564 carries named database
ranges into the clipboard document so the structured-reference tokens
in copied formulas have an ScDBData to resolve against. It only fixes
resolution though - the table itself is never re-anchored on paste.

The sole paste-side consumer, adjustDBRange() in formulacell.cxx, is
per-token: when the destination does not already own the name it clones
the ScDBData keeping the source coordinates. Pasting a fully-copied
table into another document at a different position therefore registers
the table - with its autofilter, style and structured references - over
the original, usually empty, cells, and the totals come out as #REF!.

Mirror CopyDBsToClip with a CopyDBsFromClip run once from CopyFromClip
before the cells are copied in. For every named table the copied range
fully covered, and that the destination does not already own, clone it
and MoveTo() its area by the copy-to-paste delta onto the destination
sheet. adjustDBRange() then binds the carried tokens to the correctly-
placed table by name, so the structured references resolve against the
pasted block instead of #REF!.

A same-document paste is left untouched: table names are document-
global, so the name already exists and the existing table - and the
references resolving to it - must stay as they are. Reconstructing an
independent copy there would need a fresh unique name and is out of
scope here.

Signed-off-by: Balazs Varga <balazs.varga@collabora.com>
Change-Id: I6411c9be39279b056dd07bd0129231c0e2781b3f
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/4646
Tested-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
Reviewed-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
(cherry picked from commit 3f68315c1b727be148a20baed68a01865b922231)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207000
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
2026-06-19 14:27:41 +02:00
Méven Car c40b87eea6 sc: carry named database ranges into the clipboard document
Copying cells from a sheet that has a named table (an xlsx
structured-reference table mapped to an ScDBData) left the
clipboard document's ScDBCollection empty. The clipboard
formulas still carried ocTableRefOpen tokens, so any later
textual form of those formulas - HTML clipboard generation,
"paste special as text", or even an internal row-insert
scratchpad that walks the cells through ScCompiler - resolved
the column references to nothing and wrote #REF! in place of
the column name. The same path emits a flood of
"ScCompiler::CreateStringFromSingleRef - TableRef without
ScDBData" and "TableRef of empty header-less" warnings.

Mirror CopyRangeNamesToClip with a small CopyDBsToClip that
clones every named ScDBData whose area intersects the copied
range into the clip document. The cloned entries keep the
original index so the carried ocTableRefOpen tokens resolve
to the same column-name vectors as in the source document.

Signed-off-by: Meven Car <meven.car@collabora.com>
Change-Id: I9666e93d43fa789ae9af69d8d814c1c5edd9ab2d
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/4309
Tested-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
Reviewed-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
(cherry picked from commit 135574751cddbf8b6458c87d02fa7e288b04f91b)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/206998
Tested-by: Xisco Fauli <xiscofauli@libreoffice.org>
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
2026-06-19 14:27:20 +02:00
Caolán McNamara b601b4304e crashtesting: defer dynamic-array resize during the CalcAll walk
ScTable::CalcAll interprets every formula cell in each column's cell
store. Interpreting a dynamic-array master whose result size changed
runs ResizeMatrixFormula, which deletes or inserts reference cells in
the columns being walked and frees the block the iterator sits on.

Take a MatrixResizeGuard around the whole per-table walk so any such
resize is queued and drained once, after every column. At the table
level this covers both callers, ScDocument::CalcAll and the direct
FetchTable(n)->CalcAll() in the xlsx exporter, and the per-table drain
makes the trailing ProcessPendingMatrixResizes in ScDocument::CalcAll
dead, so drop it.

forum-mso-en4-776376.xlsx aborted before this under DoHardRecalc when
saved to xlsx or ods, and converts cleanly with this.

Signed-off-by: Caolán McNamara <caolan.mcnamara@collabora.com>
Change-Id: I54cd8ce944d791339a0f2feec02bea5bb87d9312
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/4216
Reviewed-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
(cherry picked from commit 630cd3a5e5a7280cc19f80b51751de8afda2afe9)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/206659
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
2026-06-16 10:38:45 +02:00
Tomaž Vajngerl 4a903f85b8 sc: add mbDynamicArrayMaster and gate matrix auto-resize on it
Introduce a per-cell bit on ScFormulaCell that marks a matrix master
as dynamic. A matrix master with the flag set recomputes its range
at interpret time so the result grows or shrinks with the source
data. A matrix master without the flag is a static array master and
keeps its declared range frozen.

SetDynamicArrayMaster(true) on a plain single-cell formula promotes
the cell to a 1x1 matrix master so the first interpret expands it
through the auto-resize gate. Callers that opt a NONE cell into the
dynamic-array path only have to flip the one flag.

ScFormulaCell::InterpretTail uses the flag as the single opt-in for
the auto-resize path. The path fires when the cell has the dynamic
flag, or when the cell is currently in spill state and needs to
re-check on the next interpret. Static masters entered through
ScDocFunc::EnterMatrix or ScDocument::InsertMatrixFormula keep the
flag false so their declared range is the user's intent and never
changes underneath them.

InsertMatrixFormula and EnterMatrix grow a new bDynamicArrayMaster
parameter so callers can choose. The existing spill tests opt in
to keep their auto-resize behaviour. The two contraction tests in
uicalc2 entered their matrix masters with Ctrl+Shift+Enter, which
no longer drives auto-resize, so insertArrayToCell grows an opt-in
bDynamicArrayMaster parameter and those two tests pass true to
flip the master into the dynamic gate after entry.

The paste path in cliputil.cxx re-creates a matrix master at the
destination via ScDocFunc::EnterMatrix. The call now reads the
source cell's dynamic-array flag and passes it on, so a dynamic
master pasted to a new location stays a dynamic master and the
auto-resize gate keeps firing.

Importers (XLSX cm, ODS coext:spill) and the UI entry path will
set the flag in the follow-up commits.

Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>
Change-Id: Ie6fbf6972aa796f3833b726ea0184fc34ed92a3d
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/4173
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
(cherry picked from commit 006b0c6577c4e35087595cb92b629757c8c4d166)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/206674
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Tested-by: Jenkins
2026-06-16 09:14:51 +02:00