Skip to content

Fix no std with alloc - #226

Merged
Lokathor merged 2 commits into
Lokathor:mainfrom
andrew-signal:fix-no-std-with-alloc
Sep 4, 2026
Merged

Fix no std with alloc#226
Lokathor merged 2 commits into
Lokathor:mainfrom
andrew-signal:fix-no-std-with-alloc

Conversation

@andrew-signal

@andrew-signal andrew-signal commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Resolves #225.

It looks like the functionality added in #224 accidentally calls the bare vec! macro.

This was not caught in tests, because no test configuration ran with alloc but without std.

This just changes it to match invocations elsewhere, plus adds test coverage.

@QueenOfSquiggles QueenOfSquiggles left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LGTM

@QueenOfSquiggles

Copy link
Copy Markdown

I patched this branch into my current project and it solves the build issue entirely.

https://codeberg.org/QueenOfSquiggles/jktd

@JohanVonElectrum JohanVonElectrum left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LGTM

@developer0hye developer0hye left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Validated commit f3fd1f5 locally on stable aarch64-apple-darwin. cargo check --no-default-features --features=alloc,grab_spare_slice,latest_stable_rust and cargo fmt --all -- --check both pass. The qualified alloc::vec! call directly fixes the 1.13.0 no_std + alloc regression, and the added workflow command covers the previously missing feature combination. This regression is currently blocking cold unlocked builds in downstream projects, including office2pdf.

@JohanVonElectrum

Copy link
Copy Markdown

Successfully used this to fix the cold installation of sqlx-cli.
Cloned sqlx, added a patch in Cargo.toml with this branch, and it worked.

@Lokathor
Lokathor merged commit 85f21c6 into Lokathor:main Sep 4, 2026
5 checks passed
@Lokathor

Lokathor commented Sep 4, 2026

Copy link
Copy Markdown
Owner

Sorry about all this trouble everyone, 1.13.1 is released.

leynos added a commit to leynos/lille that referenced this pull request Sep 4, 2026
* Hold tinyvec at 1.12 until 1.13 builds again

`tinyvec` 1.13.0, published on 2026-09-03, imports `alloc::vec` as a module
and then invokes the `vec!` macro. On the nightly this repository pins the
macro no longer resolves:

```text
error: cannot find macro `vec` in this scope
   --> tinyvec-1.13.0/src/tinyvec.rs:710:21
note: `vec` is imported here, but it is a module, not a macro
```

The crate arrives transitively through Bevy's text and font stack, and this
workspace commits no `Cargo.lock`, so every build resolves the newest
compatible release and reaches the broken one. `make lint` and any
`--all-features` build fail on untouched `main`; the failure reproduces on a
clean detached checkout with an isolated target directory, so it is not a
local artefact.

Add a tilde requirement, which `AGENTS.md` permits for a documented lock to
patch-level updates. It is a resolution constraint only: no code in this
workspace names the crate, and the comment says so, so a later reader does not
mistake it for a dependency that can simply be dropped.

Upstream has not yanked 1.13.0. Lokathor/tinyvec#225 reports the same failure
and Lokathor/tinyvec#226 proposes the fix. Removal is tracked by
#340.

Claude-Session: https://claude.ai/code/session_01QrjNTnTwM7FmWXe5KFPMPY

* Catch a bad tinyvec resolution before the build does

The constraint had no test, so the only thing standing between a future
contributor and the broken release was a comment. Widen the requirement by
accident and the symptom is a macro error inside a crate nothing in this
workspace mentions.

`tests/dependency_resolution.rs` reads what Cargo actually resolved and fails
if `tinyvec` 1.13 or later is selected, naming the version and pointing at the
requirement. It also fails if the crate leaves the graph entirely, which is
the signal that the constraint and the test should both go.

Record the constraint in the developers guide as well: what it is for, why a
transitive dependency needs a direct requirement, why a tilde rather than a
caret, and the condition for removing it. A bare version requirement with no
explanation reads as a real dependency, and the next contributor cannot tell
whether dropping it is safe.

Claude-Session: https://claude.ai/code/session_01QrjNTnTwM7FmWXe5KFPMPY

* Say what the resolution test can and cannot catch

The guide called `tinyvec` "not a dependency", which is wrong: it is a
direct Cargo dependency whose only purpose is to bound resolution. Say
that instead, so a reader looking at `Cargo.toml` is not told the
opposite of what is there.

Both the guide and the test also implied the test runs before the build.
It does not. Cargo compiles the dependency graph before an integration
test runs, so a selected 1.13.0 fails the build first with the macro
error. What the test catches directly is the case that would otherwise
pass silently: a widened requirement whose resolved version still
compiles but sits outside the range this workspace has verified. Both
places now say that, and the guide points at `cargo tree --invert
tinyvec` for the case where the build fails first.

`ResolvedVersion` replaces the bare minor number. The old helper kept
only the second component, so a resolved 2.0.0 read as minor 0 and
passed a check meant to reject anything at or beyond 1.13, and the
failure message printed `1.[13]` rather than the version Cargo chose.
The type keeps the original text for the message and the major and minor
pair for the comparison.

Also reflow the guide paragraph to 80 columns and wrap the compiler
error in double backticks so Rustdoc renders it as one code span.

Claude-Session: https://claude.ai/code/session_01QrjNTnTwM7FmWXe5KFPMPY
mikebronner added a commit to mike-bronner/zed-laravel that referenced this pull request Sep 8, 2026
…#382)

Version 1.13.0 failed to compile for any no_std consumer. Commit 9f25466
added a bounded range to hold the transitive resolution at 1.12.0, as an
explicitly temporary measure.

Lokathor/tinyvec#226 merged on 2026-09-04 and closed issue #225. Version
1.13.1 published two minutes later, and 1.13.2 followed. The call in
src/tinyvec.rs is now qualified as alloc::vec![...].

The constraint is removed outright, not relaxed to a floor. A floor would
keep a permanent phantom direct dependency on a crate this project never
uses. It buys nothing over cargo's max-version selection, since 1.13.0
is unreachable once the upper bound is gone.

Verified from a regenerated lockfile rather than from the manifest edit:
a fresh resolution selects tinyvec 1.13.2, reached only through
sqlx -> sqlx-postgres -> stringprep -> unicode-normalization.

Fixes: #377
mikebronner added a commit to mike-bronner/zed-laravel that referenced this pull request Sep 8, 2026
#383)

* fix: 🐛 static-modifier order, comment-blind shadowing, @props default values

Three follow-ups on the component-member navigation code (#351, plus
item 8 from #339 since it lives in the same function):

- public_property_types kept one flag for two modifiers, so
  'static public string $x' slipped through — the static_modifier child
  is visited first and the visibility_modifier reset the flag. Separate
  public/is_static flags now, exactly as public_action_method_names
  already keeps them; the test pins BOTH modifier orders.
- is_template_local_binding scans a comment-blanked copy of the
  template: Blade ({{-- --}}) and HTML (<!-- -->) comments never
  execute, so a commented-out @foreach no longer shadows its loop
  variable for the rest of the file, and '<!-- @php -->' no longer
  opens a phantom block that turns every later assignment-looking line
  into a local. Blanked (newlines kept) rather than stripped, so line
  numbers stay stable. Directives in ordinary prose still bind —
  Blade genuinely compiles those; escaping them is what @@ is for.
- @props/@AWare capture only KEYS and bare entries: a quoted string
  right after => is a prop's default VALUE (['size' => 'md'] declares
  $size, never $md) and binds nothing.

* fix: 🐛 Require a comment terminator, and reuse the shared comment scanner.

Change-request items 3, 4 and 5 on #352.

blank_template_comments no longer hand-rolls a fourth comment scanner. It
blanks the spans blade_directive_tokens::blade_comment_spans returns, which
also settles the unterminated-opener rule: that scanner's regex requires the
closer, and so does Blade. CompilesComments::compileComments is a single
preg_replace with /{{--(.*?)--}}/s, which returns the input unchanged when
--}} is absent, and Blade never handles <!-- at all. Blanking to end of
input was a regression wider than the bug it fixed: one stray <!-- in a
<script> unbound every directive below it. The doc comment said the
opposite and is corrected.

Three tests passed against pre-fix code and could not detect a regression:
multiline_blade_comment_blanks_its_whole_body now asserts inside the comment
body, between the push and the pop; html_comment_does_not_open_a_php_block
asserts on the assignment-shaped line past the scan's break condition; and
uncommented_directives_still_bind_next_to_commented_ones gives the two loops
different variable names. A new test pins the terminator rule itself.

The .expect on String::from_utf8 becomes a fail-soft unwrap_or_else,
matching blade_var_rename::mask_non_code.

* refactor: ♻️ Consolidate the crate's comment maskers onto one dead-region scanner.

Issue #369 Part A, items A1 and A5.

The crate carried four implementations of "which regions does Blade not
execute", disagreeing on two axes: whether <!-- --> and @verbatim count as
dead, and what an unterminated opener does. blade_directive_tokens now owns
the only one. dead_region_spans covers Blade comments, HTML comments and
@verbatim bodies; blank_dead_regions blanks them preserving length and
newlines. blade_var_rename::mask_delimited and
livewire_resolver::blank_template_comments are deleted, and mask_non_code is
a one-line delegation kept for the rename module's own vocabulary.

The unterminated-opener rule is settled once, the way Blade settles it:
a missing terminator yields no span. CompilesComments::compileComments is a
single preg_replace with /{{--(.*?)--}}/s, which returns the input unchanged
without the closer, and Blade never handles <!-- at all. @verbatim follows
the same rule so the three cannot drift apart again.

Two behaviour changes fall out, both previously invisible to the suite and
both now pinned: blade_var_rename treats <!-- --> as dead, which its two
siblings already did, and it no longer masks an unterminated opener to end
of file, which used to make every variable below one stray <!-- un-renameable.

A1 arrives as a consequence: is_template_local_binding now runs over a
template with @verbatim bodies blanked, so a @foreach there no longer
shadows its loop variable.

The @verbatim span is its BODY, captured in group 1, not the whole match —
@verbatim and @endverbatim are themselves compiled directives and must still
tokenise for semantic highlighting.

* build: 📌 Pin tinyvec below 1.13 until the upstream no_std fix ships.

tinyvec 1.13.0, published today, does not compile for any consumer that
leaves its `std` feature off. The new `with_initial_len` calls `vec![]`,
but the crate is `no_std` and imports `alloc::vec` as a module, so the
macro is not in scope. Reported as Lokathor/tinyvec#225 with a fix open
in #226; the release is not yanked, so cargo still selects it.

It reaches us four levels down and is not a dependency we chose:
sqlx -> sqlx-postgres -> stringprep -> unicode-normalization -> tinyvec.

Cargo.lock is deliberately gitignored, so CI re-resolves every build and
took the broken release within hours of publication, on all three runners.
A bounded range in the manifest is the pin that survives that; a caret
range is not, and neither is a bare upper bound — see the comment.

Temporary. Remove when #226 releases.

* fix: 🐛 Honour Blade's @@ escape — an escaped directive executes nothing.

The crate had no handling for @@ anywhere. grep -rn '@@' src/ found only a
comment in livewire_resolver that cited @@ as the reason prose directives
are honoured, while the code ignored it.

Blade's rule, from BladeCompiler: compileStatements matches
/\B@(@?\w+(?:::\w+)?)([ \t]*)(\( [\S\s]*? \))?/x and compileStatement opens
with `if (str_contains($match[1], '@'))`, replacing the match with its own
text instead of compiling it. So the test is whether the preceding byte is
another @. A run of three or more behaves identically — \B makes the match
start at the second @, group 1 carries the leading @, and it is emitted
literally — so there is no parity rule.

is_escaped_directive lands beside the shared dead-region scanner and is
applied at the four sites that scan for directives: semantic tokens,
@verbatim region detection, template-local binding, and @use alias
extraction. Each was verified wrong before and right after by running it.

Not fixed here: blade_var_rename::in_scope_spans still treats an escaped
loop header as live. Its scanner is in blade_loops, and whether an escaped
loop scopes its variable for RENAME is a separate question from whether it
binds. Filed rather than guessed.

* fix: 🐛 An escaped @@foreach opens no loop block, and @@Endforeach closes none.

Completes the @@ escape handling from the previous commit. blade_loops
scans directive text at three sites and none of them knew about escaping:

  * LOOP_HEAD_RE in find_loop_blocks — @@foreach opened a block, so text
    below literal documentation was treated as loop scoped.
  * LOOP_END_RE in find_loop_blocks — @@Endforeach closed a live block, so
    a real loop ended at the literal text and its body fell out of scope.
    This is the dangerous direction.
  * LOOP_HEAD_RE in unbalanced_loop_head_lines — an escaped head with an
    unclosed paren was reported unbalanced, and in_scope_spans refuses a
    rename outright inside an unresolved region, so literal text could
    disable rename for the whole file.

All three consult blade_directive_tokens::is_escaped_directive rather than
re-deriving the rule.

Verified against the real compiler rather than by reading it: running
BladeCompiler::compileString from test-project/vendor gives
"@@foreach ($rows as $row)" -> "@foreach($rows as $row)" (literal),
"@@Endforeach" -> "@Endforeach", and "@@verbatim $x @endverbatim" ->
"@verbatim $x @endverbatim". The same escape is what makes Alpine bindings
work on names that collide with real directives: "<div @Class=\"a\">"
compiles to broken markup, "<div @@Class=\"a\">" renders "<div @Class=\"a\">".

Not changed: a $var inside an escaped header is still a rename site. That
is a question about editing literal display text, not about scoping.

* build: ⬆️ Take tree-sitter 0.27, drop the tinyvec pin, and guard the Blade grammar.

tree-sitter 0.27 carries two breaking changes that both reach this crate.
QueryMatch::captures became a private field behind a captures() accessor,
which broke five sites in queries.rs. Node::child_count() also changed from
usize to u32 while named_child_count() stayed usize, making the `as u32`
cast at the child() call redundant, which clippy rejects under -D warnings.
CI never reported that cast, because compilation aborted at the private-field
errors first. Verified against the vendored crate that the two counts really
did diverge (binding_rust/lib.rs:1836 and :1857), so the named_child_count()
casts in salsa_impl.rs and vendor_translations.rs stay as they are.

The tinyvec constraint goes with it. Main removed the pin in f4ace8c (#382)
once Lokathor/tinyvec#226 merged and 1.13.1 shipped the no_std fix. This
branch reached the same pin through its own commit 9f25466, which is not an
ancestor of main, so the merge base held no pin and e15b3b2 kept this
branch's addition over main's removal, with nothing flagged as a conflict.
A fresh resolution of all 290 packages selects tinyvec 1.13.2 through
sqlx -> sqlx-postgres -> stringprep -> unicode-normalization, matching main.
Removed outright rather than floored: a floor would keep a permanent phantom
direct dependency on a crate this project never uses.

The new tests guard a risk the upgrade makes sharper. build.rs fetches
tree-sitter-blade from main, not a tag, because upstream's newest release
(v0.12.3, 2025-08-25) sits 21 commits behind. Tracking main stays the right
call while upstream is not cutting releases, but it lets an upstream
regression arrive with no local change to explain it.

Four unreleased upstream changes were measured against our own extractors by
swapping the cached grammar. Two are observable and are covered:

  - An escaped @@directive inside an HTML attribute value (upstream #129).
    On v0.12.3 it yields a phantom view reference to a template the page
    never includes. At top level both grammars already yield nothing, so
    the test pins the one context where they differ.
  - Conditional attributes (upstream #130), on two surfaces: the reported
    arguments, which v0.12.3 truncates mid-identifier, and the embedded PHP
    region, which v0.12.3 omits entirely, leaving the member inside a
    conditional attribute invisible to hover and go-to-definition.

Two are not covered. Scoped slots (upstream #133) gave identical output
across sixteen shapes, because our query matches the tag name and that is
unchanged. The parser.c regeneration makes no behavioural claim. No test was
written to fill either slot.

Each test drives a public extraction surface and asserts our own behaviour;
none asserts a node kind or a parse-tree shape. All three pass on main and
fail on v0.12.3, so an upstream regression reddens the suite.

---------

Co-authored-by: Marlon Arno Basten <marlon-arno.basten@haendlerbund.de>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

vec macro import error with 1.13.0

5 participants