Skip to contentSkip to conversation

`syn` support

PATCH Applied Miguel Ojeda 4 participants 24 messages Nov 24, 2025 – Jan 5

Subsystems (4)
lore
Share & tools
lore

Miguel Ojeda

author maintainer
#0 lore raw

v2 cover `syn` support

This patch series introduces support for syn (and its dependencies):

Syn is a parsing library for parsing a stream of Rust tokens into a syntax tree of Rust source code.

Currently this library is geared toward use in Rust procedural macros, but contains some APIs that may be useful more generally.

It is the most downloaded Rust crate (according to crates.io), and it is also used by the Rust compiler itself. Having such support allows to greatly simplify writing complex macros such as pin-init. We will use it in the macros crate too.

Benno has already prepared the pin-init version based on this, and on top of that, we will be able to simplify the macros crate too. I think Jesung is working on updating the TryFrom and Into upcoming derive macros to use syn too.

The series starts with a few preparation commits (two fixes were already merged in mainline that were discovered by this series), then each crate is added. Finally, support for using the new crates from our macros crate is introduced.

This has been a long time coming, e.g. even before Rust for Linux was merged into the Linux kernel, Gary and Benno have wanted to use syn. The first iterations of this, from 2022 and 2023 (with serde too, another popular crate), are at:

    https://github.com/Rust-for-Linux/linux/pull/910
    https://github.com/Rust-for-Linux/linux/pull/1007

After those, we considered picking these from the distributions where possible. However, after discussing it, it is not really worth the
complexity: vendoring makes things less complex and is less fragile.

In particular, we avoid having to support and test several versions, we avoid having to introduce Cargo just to properly fetch the right versions from the registry, we can easily customize the crates if needed (e.g. dropping the unicode_idents dependency like it is done in this series) and we simplify the configuration of the build for users for which the "default" paths/registries would not have worked.

Moreover, nowadays, the ~57k lines introduced are not that much compared to years ago (it dwarfed the actual Rust kernel code). Moreover, back then it wasn't clear the Rust experiment would be a success, so it would have been a bit pointless/risky to add many lines for nothing. Our macro needs were also smaller in the early days.

So, finally, in Kangrejos 2025 we discussed going with the original, simpler approach. Thus here it is the result.

There should not be many updates needed for these, and even if there are, they should not be too big, e.g. +7k -3k lines across the 3 crates in the last year.

Note that syn does not have all the features enabled, since we do not need them so far, but they can easily be enabled just adding them to the list.

v2:
- Drop condvar patch.
- Add note about := in commit log.
- Add comment about rustfmt and note it in the log.
- Rename hostlibrary to procmacrolibrary.
- Split a couple changes into two new commits (rustc_test_library, rustc_procmacro). I applied the tags to those, since the changes are still the same and the log is simple.
- Add new commit with the macros support for the new crates.

v1: https://lore.kernel.org/rust-for-linux/[email protected]/

Miguel Ojeda (20):
rust: kbuild: introduce core-flags and core-skip_flags
rust: kbuild: simplify --cfg handling
rust: kbuild: add proc macro library support
rust: kbuild: support skipping flags in rustc_test_library
rust: kbuild: support using libraries in rustc_procmacro
rust: proc-macro2: import crate
rust: proc-macro2: add SPDX License Identifiers
rust: proc-macro2: remove unicode_ident dependency
rust: proc-macro2: add README.md
rust: proc-macro2: enable support in kbuild
rust: quote: import crate
rust: quote: add SPDX License Identifiers
rust: quote: add README.md
rust: quote: enable support in kbuild
rust: syn: import crate
rust: syn: add SPDX License Identifiers
rust: syn: remove unicode-ident dependency
rust: syn: add README.md
rust: syn: enable support in kbuild
rust: macros: support proc-macro2, quote and syn

 .gitignore                                    |    1 +
 Makefile                                      |    7 +
 rust/Makefile                                 |  147 +-
 rust/proc-macro2/README.md                    |   13 +
 rust/proc-macro2/detection.rs                 |   77 +
 rust/proc-macro2/extra.rs                     |  153 +
 rust/proc-macro2/fallback.rs                  | 1258 +++++
 rust/proc-macro2/lib.rs                       | 1351 ++++++
 rust/proc-macro2/location.rs                  |   31 +
 rust/proc-macro2/marker.rs                    |   19 +
 rust/proc-macro2/parse.rs                     |  997 ++++
 rust/proc-macro2/probe.rs                     |   12 +
 rust/proc-macro2/probe/proc_macro_span.rs     |   53 +
 .../proc-macro2/probe/proc_macro_span_file.rs |   16 +
 .../probe/proc_macro_span_location.rs         |   23 +
 rust/proc-macro2/rcvec.rs                     |  148 +
 rust/proc-macro2/wrapper.rs                   |  986 ++++
 rust/quote/README.md                          |   12 +
 rust/quote/ext.rs                             |  112 +
 rust/quote/format.rs                          |  170 +
 rust/quote/ident_fragment.rs                  |   90 +
 rust/quote/lib.rs                             | 1456 ++++++
 rust/quote/runtime.rs                         |  494 ++
 rust/quote/spanned.rs                         |   52 +
 rust/quote/to_tokens.rs                       |  273 ++
 rust/syn/README.md                            |   13 +
 rust/syn/attr.rs                              |  838 ++++
 rust/syn/bigint.rs                            |   68 +
 rust/syn/buffer.rs                            |  436 ++
 rust/syn/classify.rs                          |  313 ++
 rust/syn/custom_keyword.rs                    |  262 ++
 rust/syn/custom_punctuation.rs                |  306 ++
 rust/syn/data.rs                              |  426 ++
 rust/syn/derive.rs                            |  261 ++
 rust/syn/discouraged.rs                       |  227 +
 rust/syn/drops.rs                             |   60 +
 rust/syn/error.rs                             |  469 ++
 rust/syn/export.rs                            |   75 +
 rust/syn/expr.rs                              | 4175 +++++++++++++++++
 rust/syn/ext.rs                               |  138 +
 rust/syn/file.rs                              |  127 +
 rust/syn/fixup.rs                             |  775 +++
 rust/syn/gen/clone.rs                         | 2269 +++++++++
 rust/syn/gen/debug.rs                         | 3240 +++++++++++++
 rust/syn/gen/eq.rs                            | 2308 +++++++++
 rust/syn/gen/fold.rs                          | 3904 +++++++++++++++
 rust/syn/gen/hash.rs                          | 2878 ++++++++++++
 rust/syn/gen/visit.rs                         | 3943 ++++++++++++++++
 rust/syn/gen/visit_mut.rs                     | 3761 +++++++++++++++
 rust/syn/generics.rs                          | 1479 ++++++
 rust/syn/group.rs                             |  293 ++
 rust/syn/ident.rs                             |  110 +
 rust/syn/item.rs                              | 3492 ++++++++++++++
 rust/syn/lib.rs                               | 1013 ++++
 rust/syn/lifetime.rs                          |  158 +
 rust/syn/lit.rs                               | 1862 ++++++++
 rust/syn/lookahead.rs                         |  334 ++
 rust/syn/mac.rs                               |  227 +
 rust/syn/macros.rs                            |  184 +
 rust/syn/meta.rs                              |  429 ++
 rust/syn/op.rs                                |  221 +
 rust/syn/parse.rs                             | 1421 ++++++
 rust/syn/parse_macro_input.rs                 |  130 +
 rust/syn/parse_quote.rs                       |  242 +
 rust/syn/pat.rs                               |  957 ++++
 rust/syn/path.rs                              |  968 ++++
 rust/syn/precedence.rs                        |  212 +
 rust/syn/print.rs                             |   18 +
 rust/syn/punctuated.rs                        | 1157 +++++
 rust/syn/restriction.rs                       |  180 +
 rust/syn/scan_expr.rs                         |  267 ++
 rust/syn/sealed.rs                            |    6 +
 rust/syn/span.rs                              |   65 +
 rust/syn/spanned.rs                           |  120 +
 rust/syn/stmt.rs                              |  486 ++
 rust/syn/thread.rs                            |   62 +
 rust/syn/token.rs                             | 1098 +++++
 rust/syn/tt.rs                                |  109 +
 rust/syn/ty.rs                                | 1273 +++++
 rust/syn/verbatim.rs                          |   35 +
 rust/syn/whitespace.rs                        |   67 +
 scripts/generate_rust_analyzer.py             |   25 +-
 82 files changed, 57906 insertions(+), 17 deletions(-)
 create mode 100644 rust/proc-macro2/README.md
 create mode 100644 rust/proc-macro2/detection.rs
 create mode 100644 rust/proc-macro2/extra.rs
 create mode 100644 rust/proc-macro2/fallback.rs
 create mode 100644 rust/proc-macro2/lib.rs
 create mode 100644 rust/proc-macro2/location.rs
 create mode 100644 rust/proc-macro2/marker.rs
 create mode 100644 rust/proc-macro2/parse.rs
 create mode 100644 rust/proc-macro2/probe.rs
 create mode 100644 rust/proc-macro2/probe/proc_macro_span.rs
 create mode 100644 rust/proc-macro2/probe/proc_macro_span_file.rs
 create mode 100644 rust/proc-macro2/probe/proc_macro_span_location.rs
 create mode 100644 rust/proc-macro2/rcvec.rs
 create mode 100644 rust/proc-macro2/wrapper.rs
 create mode 100644 rust/quote/README.md
 create mode 100644 rust/quote/ext.rs
 create mode 100644 rust/quote/format.rs
 create mode 100644 rust/quote/ident_fragment.rs
 create mode 100644 rust/quote/lib.rs
 create mode 100644 rust/quote/runtime.rs
 create mode 100644 rust/quote/spanned.rs
 create mode 100644 rust/quote/to_tokens.rs
 create mode 100644 rust/syn/README.md
 create mode 100644 rust/syn/attr.rs
 create mode 100644 rust/syn/bigint.rs
 create mode 100644 rust/syn/buffer.rs
 create mode 100644 rust/syn/classify.rs
 create mode 100644 rust/syn/custom_keyword.rs
 create mode 100644 rust/syn/custom_punctuation.rs
 create mode 100644 rust/syn/data.rs
 create mode 100644 rust/syn/derive.rs
 create mode 100644 rust/syn/discouraged.rs
 create mode 100644 rust/syn/drops.rs
 create mode 100644 rust/syn/error.rs
 create mode 100644 rust/syn/export.rs
 create mode 100644 rust/syn/expr.rs
 create mode 100644 rust/syn/ext.rs
 create mode 100644 rust/syn/file.rs
 create mode 100644 rust/syn/fixup.rs
 create mode 100644 rust/syn/gen/clone.rs
 create mode 100644 rust/syn/gen/debug.rs
 create mode 100644 rust/syn/gen/eq.rs
 create mode 100644 rust/syn/gen/fold.rs
 create mode 100644 rust/syn/gen/hash.rs
 create mode 100644 rust/syn/gen/visit.rs
 create mode 100644 rust/syn/gen/visit_mut.rs
 create mode 100644 rust/syn/generics.rs
 create mode 100644 rust/syn/group.rs
 create mode 100644 rust/syn/ident.rs
 create mode 100644 rust/syn/item.rs
 create mode 100644 rust/syn/lib.rs
 create mode 100644 rust/syn/lifetime.rs
 create mode 100644 rust/syn/lit.rs
 create mode 100644 rust/syn/lookahead.rs
 create mode 100644 rust/syn/mac.rs
 create mode 100644 rust/syn/macros.rs
 create mode 100644 rust/syn/meta.rs
 create mode 100644 rust/syn/op.rs
 create mode 100644 rust/syn/parse.rs
 create mode 100644 rust/syn/parse_macro_input.rs
 create mode 100644 rust/syn/parse_quote.rs
 create mode 100644 rust/syn/pat.rs
 create mode 100644 rust/syn/path.rs
 create mode 100644 rust/syn/precedence.rs
 create mode 100644 rust/syn/print.rs
 create mode 100644 rust/syn/punctuated.rs
 create mode 100644 rust/syn/restriction.rs
 create mode 100644 rust/syn/scan_expr.rs
 create mode 100644 rust/syn/sealed.rs
 create mode 100644 rust/syn/span.rs
 create mode 100644 rust/syn/spanned.rs
 create mode 100644 rust/syn/stmt.rs
 create mode 100644 rust/syn/thread.rs
 create mode 100644 rust/syn/token.rs
 create mode 100644 rust/syn/tt.rs
 create mode 100644 rust/syn/ty.rs
 create mode 100644 rust/syn/verbatim.rs
 create mode 100644 rust/syn/whitespace.rs

base-commit: bc197e24a3acd13dd0b7b07c1448c5c225946546 --
2.52.0

author maintainer
#1 lore raw

PATCH v2 1/20 rust: kbuild: introduce `core-flags` and `core-skip_flags`

In the next commits we are introducing *-{cfgs,skip_flags,flags} variables for other crates.

Thus do so here for core, which simplifies a bit the Makefile (including the next commit) and makes it more consistent.

This means we stop passing -Wrustdoc::unescaped_backticks to rustc and -Wunreachable_pub to rustdoc, i.e. we skip more, which is fine since it shouldn't have an effect.

In addition, use := for core-cfgs to make it consistent with the upcoming additions.

---
 rust/Makefile | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)
rust/Makefile +14 -5
index 23c7ae905bd2..ce1853a09d3d 100644
@@ -60,11 +60,20 @@ rustdoc_test_quiet=--test-args -q
 rustdoc_test_kernel_quiet=>/dev/null
 endif
 
-core-cfgs = \
+core-cfgs := \
     --cfg no_fp_fmt_parse
 
 core-edition := $(if $(call rustc-min-version,108700),2024,2021)
 
+core-skip_flags := \
+    --edition=2021 \
+    -Wunreachable_pub \
+    -Wrustdoc::unescaped_backticks
+
+core-flags := \
+    --edition=$(core-edition) \
+    $(core-cfgs)
+
 # `rustdoc` did not save the target modifiers, thus workaround for
 # the time being (https://github.com/rust-lang/rust/issues/144521).
 rustdoc_modifiers_workaround := $(if $(call rustc-min-version,108800),-Cunsafe-allow-abi-mismatch=fixed-x18)
@@ -122,8 +131,8 @@ rustdoc-macros: $(src)/macros/lib.rs rustdoc-clean FORCE
 
 # Starting with Rust 1.82.0, skipping `-Wrustdoc::unescaped_backticks` should
 # not be needed -- see https://github.com/rust-lang/rust/pull/128307.
-rustdoc-core: private skip_flags = --edition=2021 -Wrustdoc::unescaped_backticks
-rustdoc-core: private rustc_target_flags = --edition=$(core-edition) $(core-cfgs)
+rustdoc-core: private skip_flags = $(core-skip_flags)
+rustdoc-core: private rustc_target_flags = $(core-flags)
 rustdoc-core: $(RUST_LIB_SRC)/core/src/lib.rs rustdoc-clean FORCE
 	+$(call if_changed,rustdoc)
 
@@ -499,9 +508,9 @@ $(obj)/helpers/helpers.o: $(src)/helpers/helpers.c $(recordmcount_source) FORCE
 $(obj)/exports.o: private skip_gendwarfksyms = 1
 
 $(obj)/core.o: private skip_clippy = 1
-$(obj)/core.o: private skip_flags = --edition=2021 -Wunreachable_pub
+$(obj)/core.o: private skip_flags = $(core-skip_flags)
 $(obj)/core.o: private rustc_objcopy = $(foreach sym,$(redirect-intrinsics),--redefine-sym $(sym)=__rust$(sym))
-$(obj)/core.o: private rustc_target_flags = --edition=$(core-edition) $(core-cfgs)
+$(obj)/core.o: private rustc_target_flags = $(core-flags)
 $(obj)/core.o: $(RUST_LIB_SRC)/core/src/lib.rs \
     $(wildcard $(objtree)/include/config/RUSTC_VERSION_TEXT) FORCE
 	+$(call if_changed_rule,rustc_library)
Signature · 1 line
2.52.0
author maintainer
#2 lore raw

PATCH v2 2/20 rust: kbuild: simplify `--cfg` handling

In reply to Miguel Ojeda

We need to handle cfgs in both rustc and rust-analyzer, and in future commits some of those contain double quotes, which complicates things further.

Thus, instead of removing the --cfg part in the rust-analyzer generation script, have the *-cfgs variables contain just the actual cfg, and use that to generate the actual flags in *-flags.

---
 rust/Makefile                     | 6 ++++--
 scripts/generate_rust_analyzer.py | 2 +-
 2 files changed, 5 insertions(+), 3 deletions(-)
rust/Makefile +4 -2
index ce1853a09d3d..9967f3457d44 100644
@@ -60,8 +60,10 @@ rustdoc_test_quiet=--test-args -q
 rustdoc_test_kernel_quiet=>/dev/null
 endif
 
+cfgs-to-flags = $(patsubst %,--cfg='%',$1)
+
 core-cfgs := \
-    --cfg no_fp_fmt_parse
+    no_fp_fmt_parse
 
 core-edition := $(if $(call rustc-min-version,108700),2024,2021)
 
@@ -72,7 +74,7 @@ core-skip_flags := \
 
 core-flags := \
     --edition=$(core-edition) \
-    $(core-cfgs)
+    $(call cfgs-to-flags,$(core-cfgs))
 
 # `rustdoc` did not save the target modifiers, thus workaround for
 # the time being (https://github.com/rust-lang/rust/issues/144521).
scripts/generate_rust_analyzer.py +1 -1
index fc27f0cca752..dedca470adc1 100755
@@ -15,7 +15,7 @@ def args_crates_cfgs(cfgs):
     crates_cfgs = {}
     for cfg in cfgs:
         crate, vals = cfg.split("=", 1)
-        crates_cfgs[crate] = vals.replace("--cfg", "").split()
+        crates_cfgs[crate] = vals.split()
 
     return crates_cfgs
 
Signature · 1 line
2.52.0
author maintainer
#3 lore raw

PATCH v2 3/20 rust: kbuild: add proc macro library support

In reply to Miguel Ojeda

Add the proc macro library rule that produces .rlib files to be used by proc macros such as the macros crate.

---
 .gitignore    |  1 +
 rust/Makefile | 10 ++++++++++
 2 files changed, 11 insertions(+)
.gitignore +1 -0
index 86a1ba0d9035..3a7241c941f5 100644
@@ -41,6 +41,7 @@
 *.o.*
 *.patch
 *.pyc
+*.rlib
 *.rmeta
 *.rpm
 *.rsi
rust/Makefile +10 -0
index 9967f3457d44..45ef84513b6c 100644
@@ -421,6 +421,16 @@ $(obj)/exports_bindings_generated.h: $(obj)/bindings.o FORCE
 $(obj)/exports_kernel_generated.h: $(obj)/kernel.o FORCE
 	$(call if_changed,exports)
 
+quiet_cmd_rustc_procmacrolibrary = $(RUSTC_OR_CLIPPY_QUIET) PL $@
+      cmd_rustc_procmacrolibrary = \
+	$(if $(skip_clippy),$(RUSTC),$(RUSTC_OR_CLIPPY)) \
+		$(filter-out $(skip_flags),$(rust_common_flags) $(rustc_target_flags)) \
+		--emit=dep-info,link --crate-type rlib -O \
+		--out-dir $(objtree)/$(obj) -L$(objtree)/$(obj) \
+		--crate-name $(patsubst lib%.rlib,%,$(notdir $@)) $<; \
+	mv $(objtree)/$(obj)/$(patsubst lib%.rlib,%,$(notdir $@)).d $(depfile); \
+	sed -i '/^\#/d' $(depfile)
+
 quiet_cmd_rustc_procmacro = $(RUSTC_OR_CLIPPY_QUIET) P $@
       cmd_rustc_procmacro = \
 	$(RUSTC_OR_CLIPPY) $(rust_common_flags) $(rustc_target_flags) \
Signature · 1 line
2.52.0
author maintainer
#4 lore raw

PATCH v2 4/20 rust: kbuild: support skipping flags in `rustc_test_library`

In reply to Miguel Ojeda

Crates like quote (added later) will need the ability to skip flags in the rustc_test_library command.

Thus add the support for it.

---
 rust/Makefile | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
rust/Makefile +2 -2
index 45ef84513b6c..6fdab341fc48 100644
@@ -172,8 +172,8 @@ rustdoc-clean: FORCE
 quiet_cmd_rustc_test_library = $(RUSTC_OR_CLIPPY_QUIET) TL $<
       cmd_rustc_test_library = \
 	OBJTREE=$(abspath $(objtree)) \
-	$(RUSTC_OR_CLIPPY) $(rust_common_flags) \
-		@$(objtree)/include/generated/rustc_cfg $(rustc_target_flags) \
+	$(RUSTC_OR_CLIPPY) $(filter-out $(skip_flags),$(rust_common_flags) $(rustc_target_flags)) \
+		@$(objtree)/include/generated/rustc_cfg \
 		--crate-type $(if $(rustc_test_library_proc),proc-macro,rlib) \
 		--out-dir $(objtree)/$(obj)/test --cfg testlib \
 		-L$(objtree)/$(obj)/test \
Signature · 1 line
2.52.0
author maintainer
#5 lore raw

PATCH v2 5/20 rust: kbuild: support using libraries in `rustc_procmacro`

In reply to Miguel Ojeda

Proc macros such as macros and pin-init will need the ability to use libraries such as syn (added later) in the rustc_procmacro command.

Thus add the support for it.

---
 rust/Makefile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
rust/Makefile +1 -1
index 6fdab341fc48..0288ca8d270c 100644
@@ -437,7 +437,7 @@ quiet_cmd_rustc_procmacro = $(RUSTC_OR_CLIPPY_QUIET) P $@
 		-Clinker-flavor=gcc -Clinker=$(HOSTCC) \
 		-Clink-args='$(call escsq,$(KBUILD_PROCMACROLDFLAGS))' \
 		--emit=dep-info=$(depfile) --emit=link=$@ --extern proc_macro \
-		--crate-type proc-macro \
+		--crate-type proc-macro -L$(objtree)/$(obj) \
 		--crate-name $(patsubst lib%.$(libmacros_extension),%,$(notdir $@)) \
 		@$(objtree)/include/generated/rustc_cfg $<
 
Signature · 1 line
2.52.0
author maintainer
#6 lore raw

PATCH v2 6/20 rust: proc-macro2: import crate

In reply to Miguel Ojeda

This is a subset of the Rust proc-macro2 crate, version 1.0.101 (released 2025-08-16), licensed under "Apache-2.0 OR MIT", from:

    https://github.com/dtolnay/proc-macro2/raw/1.0.101/src

The files are copied as-is, with no modifications whatsoever (not even adding the SPDX identifiers).

For copyright details, please see:

    https://github.com/dtolnay/proc-macro2/blob/1.0.101/README.md#license
    https://github.com/dtolnay/proc-macro2/blob/1.0.101/LICENSE-APACHE
    https://github.com/dtolnay/proc-macro2/blob/1.0.101/LICENSE-MIT

The next two patches modify these files as needed for use within the kernel. This patch split allows reviewers to double-check the import and to clearly see the differences introduced.

The following script may be used to verify the contents:

    for path in $(cd rust/proc-macro2/ && find . -type f -name '*.rs'); do
        curl --silent --show-error --location \
            https://github.com/dtolnay/proc-macro2/raw/1.0.101/src/$path \
            | diff --unified rust/proc-macro2/$path - && echo $path: OK
    done
---
 rust/proc-macro2/detection.rs                 |   75 +
 rust/proc-macro2/extra.rs                     |  151 ++
 rust/proc-macro2/fallback.rs                  | 1256 +++++++++++++++
 rust/proc-macro2/lib.rs                       | 1349 +++++++++++++++++
 rust/proc-macro2/location.rs                  |   29 +
 rust/proc-macro2/marker.rs                    |   17 +
 rust/proc-macro2/parse.rs                     |  995 ++++++++++++
 rust/proc-macro2/probe.rs                     |   10 +
 rust/proc-macro2/probe/proc_macro_span.rs     |   51 +
 .../proc-macro2/probe/proc_macro_span_file.rs |   14 +
 .../probe/proc_macro_span_location.rs         |   21 +
 rust/proc-macro2/rcvec.rs                     |  146 ++
 rust/proc-macro2/wrapper.rs                   |  984 ++++++++++++
 13 files changed, 5098 insertions(+)
 create mode 100644 rust/proc-macro2/detection.rs
 create mode 100644 rust/proc-macro2/extra.rs
 create mode 100644 rust/proc-macro2/fallback.rs
 create mode 100644 rust/proc-macro2/lib.rs
 create mode 100644 rust/proc-macro2/location.rs
 create mode 100644 rust/proc-macro2/marker.rs
 create mode 100644 rust/proc-macro2/parse.rs
 create mode 100644 rust/proc-macro2/probe.rs
 create mode 100644 rust/proc-macro2/probe/proc_macro_span.rs
 create mode 100644 rust/proc-macro2/probe/proc_macro_span_file.rs
 create mode 100644 rust/proc-macro2/probe/proc_macro_span_location.rs
 create mode 100644 rust/proc-macro2/rcvec.rs
 create mode 100644 rust/proc-macro2/wrapper.rs
rust/proc-macro2/detection.rs new file +75 -0
new file mode 100644
index 000000000000..beba7b237395
@@ -0,0 +1,75 @@
+use core::sync::atomic::{AtomicUsize, Ordering};
+use std::sync::Once;
+
+static WORKS: AtomicUsize = AtomicUsize::new(0);
+static INIT: Once = Once::new();
+
+pub(crate) fn inside_proc_macro() -> bool {
+    match WORKS.load(Ordering::Relaxed) {
+        1 => return false,
+        2 => return true,
+        _ => {}
+    }
+
+    INIT.call_once(initialize);
+    inside_proc_macro()
+}
+
+pub(crate) fn force_fallback() {
+    WORKS.store(1, Ordering::Relaxed);
+}
+
+pub(crate) fn unforce_fallback() {
+    initialize();
+}
+
+#[cfg(not(no_is_available))]
+fn initialize() {
+    let available = proc_macro::is_available();
+    WORKS.store(available as usize + 1, Ordering::Relaxed);
+}
+
+// Swap in a null panic hook to avoid printing "thread panicked" to stderr,
+// then use catch_unwind to determine whether the compiler's proc_macro is
+// working. When proc-macro2 is used from outside of a procedural macro all
+// of the proc_macro crate's APIs currently panic.
+//
+// The Once is to prevent the possibility of this ordering:
+//
+//     thread 1 calls take_hook, gets the user's original hook
+//     thread 1 calls set_hook with the null hook
+//     thread 2 calls take_hook, thinks null hook is the original hook
+//     thread 2 calls set_hook with the null hook
+//     thread 1 calls set_hook with the actual original hook
+//     thread 2 calls set_hook with what it thinks is the original hook
+//
+// in which the user's hook has been lost.
+//
+// There is still a race condition where a panic in a different thread can
+// happen during the interval that the user's original panic hook is
+// unregistered such that their hook is incorrectly not called. This is
+// sufficiently unlikely and less bad than printing panic messages to stderr
+// on correct use of this crate. Maybe there is a libstd feature request
+// here. For now, if a user needs to guarantee that this failure mode does
+// not occur, they need to call e.g. `proc_macro2::Span::call_site()` from
+// the main thread before launching any other threads.
+#[cfg(no_is_available)]
+fn initialize() {
+    use std::panic::{self, PanicInfo};
+
+    type PanicHook = dyn Fn(&PanicInfo) + Sync + Send + 'static;
+
+    let null_hook: Box<PanicHook> = Box::new(|_panic_info| { /* ignore */ });
+    let sanity_check = &*null_hook as *const PanicHook;
+    let original_hook = panic::take_hook();
+    panic::set_hook(null_hook);
+
+    let works = panic::catch_unwind(proc_macro::Span::call_site).is_ok();
+    WORKS.store(works as usize + 1, Ordering::Relaxed);
+
+    let hopefully_null_hook = panic::take_hook();
+    panic::set_hook(original_hook);
+    if sanity_check != &*hopefully_null_hook {
+        panic!("observed race condition in proc_macro2::inside_proc_macro");
+    }
+}
rust/proc-macro2/extra.rs new file +151 -0

151 lines not on this page · raw message

rust/proc-macro2/fallback.rs new file +1256 -0

1,256 lines not on this page · raw message

rust/proc-macro2/lib.rs new file +1349 -0

1,349 lines not on this page · raw message

rust/proc-macro2/location.rs new file +29 -0
new file mode 100644
index 000000000000..7190e2d05255
@@ -0,0 +1,29 @@
+use core::cmp::Ordering;
+
+/// A line-column pair representing the start or end of a `Span`.
+///
+/// This type is semver exempt and not exposed by default.
+#[cfg_attr(docsrs, doc(cfg(feature = "span-locations")))]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+pub struct LineColumn {
+    /// The 1-indexed line in the source file on which the span starts or ends
+    /// (inclusive).
+    pub line: usize,
+    /// The 0-indexed column (in UTF-8 characters) in the source file on which
+    /// the span starts or ends (inclusive).
+    pub column: usize,
+}
+
+impl Ord for LineColumn {
+    fn cmp(&self, other: &Self) -> Ordering {
+        self.line
+            .cmp(&other.line)
+            .then(self.column.cmp(&other.column))
+    }
+}
+
+impl PartialOrd for LineColumn {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
rust/proc-macro2/marker.rs new file +17 -0
new file mode 100644
index 000000000000..23b94ce6fa85
@@ -0,0 +1,17 @@
+use alloc::rc::Rc;
+use core::marker::PhantomData;
+use core::panic::{RefUnwindSafe, UnwindSafe};
+
+// Zero sized marker with the correct set of autotrait impls we want all proc
+// macro types to have.
+#[derive(Copy, Clone)]
+#[cfg_attr(
+    all(procmacro2_semver_exempt, any(not(wrap_proc_macro), super_unstable)),
+    derive(PartialEq, Eq)
+)]
+pub(crate) struct ProcMacroAutoTraits(PhantomData<Rc<()>>);
+
+pub(crate) const MARKER: ProcMacroAutoTraits = ProcMacroAutoTraits(PhantomData);
+
+impl UnwindSafe for ProcMacroAutoTraits {}
+impl RefUnwindSafe for ProcMacroAutoTraits {}
rust/proc-macro2/parse.rs new file +995 -0

123 lines not on this page · raw message

rust/proc-macro2/probe.rs new file +10 -0
new file mode 100644
index 000000000000..b67f52036218

Lines of this file are not shown. View the raw message.

rust/proc-macro2/probe/proc_macro_span.rs new file +51 -0

51 lines not on this page · raw message

rust/proc-macro2/probe/proc_macro_span_file.rs new file +14 -0
new file mode 100644
index 000000000000..8b76bdf5007b

Lines of this file are not shown. View the raw message.

rust/proc-macro2/probe/proc_macro_span_location.rs new file +21 -0
new file mode 100644
index 000000000000..79da34af54af

Lines of this file are not shown. View the raw message.

rust/proc-macro2/rcvec.rs new file +146 -0

146 lines not on this page · raw message

rust/proc-macro2/wrapper.rs new file +984 -0

984 lines not on this page · raw message

The rest of this diff is not shown. View the raw message.

Signature · 1 line
2.52.0

Part of the diff is not shown here. View the raw message.

author maintainer
#7 lore raw

PATCH v2 7/20 rust: proc-macro2: add SPDX License Identifiers

In reply to Miguel Ojeda

Originally, when the Rust upstream alloc standard library crate was vendored in commit 057b8d257107 ("rust: adapt alloc crate to the kernel"), the SPDX License Identifiers were added to every file so that the license on those was clear.

Thus do the same for the proc-macro2 crate.

This makes scripts/spdxcheck.py pass.

---
 rust/proc-macro2/detection.rs                      | 2 ++
 rust/proc-macro2/extra.rs                          | 2 ++
 rust/proc-macro2/fallback.rs                       | 2 ++
 rust/proc-macro2/lib.rs                            | 2 ++
 rust/proc-macro2/location.rs                       | 2 ++
 rust/proc-macro2/marker.rs                         | 2 ++
 rust/proc-macro2/parse.rs                          | 2 ++
 rust/proc-macro2/probe.rs                          | 2 ++
 rust/proc-macro2/probe/proc_macro_span.rs          | 2 ++
 rust/proc-macro2/probe/proc_macro_span_file.rs     | 2 ++
 rust/proc-macro2/probe/proc_macro_span_location.rs | 2 ++
 rust/proc-macro2/rcvec.rs                          | 2 ++
 rust/proc-macro2/wrapper.rs                        | 2 ++
 13 files changed, 26 insertions(+)
rust/proc-macro2/detection.rs +2 -0
index beba7b237395..3de448cb2dde 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 use core::sync::atomic::{AtomicUsize, Ordering};
 use std::sync::Once;
 
rust/proc-macro2/extra.rs +2 -0
index 522a90e136be..55feb5ec7526 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 //! Items which do not have a correspondence to any API in the proc_macro crate,
 //! but are necessary to include in proc-macro2.
 
rust/proc-macro2/fallback.rs +2 -0
index 1560105cfd25..9e005d67f7f5 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 #[cfg(wrap_proc_macro)]
 use crate::imp;
 #[cfg(span_locations)]
rust/proc-macro2/lib.rs +2 -0
index 2984af335adc..7b78d065d51c 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 //! [![github]](https://github.com/dtolnay/proc-macro2)&ensp;[![crates-io]](https://crates.io/crates/proc-macro2)&ensp;[![docs-rs]](crate)
 //!
 //! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
rust/proc-macro2/location.rs +2 -0
index 7190e2d05255..3a11871e2943 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 use core::cmp::Ordering;
 
 /// A line-column pair representing the start or end of a `Span`.
rust/proc-macro2/marker.rs +2 -0
index 23b94ce6fa85..6f322424808c 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 use alloc::rc::Rc;
 use core::marker::PhantomData;
 use core::panic::{RefUnwindSafe, UnwindSafe};
rust/proc-macro2/parse.rs +2 -0
index b8be403f842f..a005dea1fe88 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 use crate::fallback::{
     self, is_ident_continue, is_ident_start, Group, Ident, LexError, Literal, Span, TokenStream,
     TokenStreamBuilder,
rust/proc-macro2/probe.rs +2 -0
index b67f52036218..d68aa8cfd85e 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 #![allow(dead_code)]
 
 #[cfg(proc_macro_span)]
rust/proc-macro2/probe/proc_macro_span.rs +2 -0
index 2d7d44e07708..892a7eb3e5a0 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 // This code exercises the surface area that we expect of Span's unstable API.
 // If the current toolchain is able to compile it, then proc-macro2 is able to
 // offer these APIs too.
rust/proc-macro2/probe/proc_macro_span_file.rs +2 -0
index 8b76bdf5007b..f2dbc4056ebe 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 // The subset of Span's API stabilized in Rust 1.88.
 
 extern crate proc_macro;
rust/proc-macro2/probe/proc_macro_span_location.rs +2 -0
index 79da34af54af..ae19c93394fa 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 // The subset of Span's API stabilized in Rust 1.88.
 
 extern crate proc_macro;
rust/proc-macro2/rcvec.rs +2 -0
index 23edc77d597f..e224ebe277ef 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 use alloc::rc::Rc;
 use alloc::vec;
 use core::mem;
rust/proc-macro2/wrapper.rs +2 -0
index 2e3eb5b4d04e..6792e9834111 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 use crate::detection::inside_proc_macro;
 use crate::fallback::{self, FromStr2 as _};
 #[cfg(span_locations)]
Signature · 1 line
2.52.0
author maintainer
#8 lore raw

PATCH v2 8/20 rust: proc-macro2: remove `unicode_ident` dependency

In reply to Miguel Ojeda

The proc-macro2 crate depends on the unicode-ident crate to determine whether characters have the XID_Start or XID_Continue properties according to Unicode Standard Annex #31.

However, we only need ASCII identifiers in the kernel, thus we can simplify the check and remove completely that dependency.

---
 rust/proc-macro2/fallback.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
rust/proc-macro2/fallback.rs +2 -2
index 9e005d67f7f5..9b43c97df97a 100644
@@ -818,11 +818,11 @@ pub(crate) fn set_span(&mut self, span: Span) {
 }
 
 pub(crate) fn is_ident_start(c: char) -> bool {
-    c == '_' || unicode_ident::is_xid_start(c)
+    c == '_' || c.is_ascii_alphabetic()
 }
 
 pub(crate) fn is_ident_continue(c: char) -> bool {
-    unicode_ident::is_xid_continue(c)
+    c == '_' || c.is_ascii_alphanumeric()
 }
 
 #[track_caller]
Signature · 1 line
2.52.0
author maintainer
#9 lore raw

PATCH v2 9/20 rust: proc-macro2: add `README.md`

In reply to Miguel Ojeda

Originally, when the Rust upstream alloc standard library crate was vendored in commit 057b8d257107 ("rust: adapt alloc crate to the kernel"), a README.md file was added to explain the provenance and licensing of the source files.

Thus do the same for the proc-macro2 crate.

---
 rust/proc-macro2/README.md | 13 +++++++++++++
 1 file changed, 13 insertions(+)
 create mode 100644 rust/proc-macro2/README.md
rust/proc-macro2/README.md new file +13 -0
new file mode 100644
index 000000000000..af044fee4f59
@@ -0,0 +1,13 @@
+# `proc-macro2`
+
+These source files come from the Rust `proc-macro2` crate, version
+1.0.101 (released 2025-08-16), hosted in the
+<https://github.com/dtolnay/proc-macro2> repository, licensed under
+"Apache-2.0 OR MIT" and only modified to add the SPDX license
+identifiers and to remove the `unicode-ident` dependency.
+
+For copyright details, please see:
+
+    https://github.com/dtolnay/proc-macro2/blob/1.0.101/README.md#license
+    https://github.com/dtolnay/proc-macro2/blob/1.0.101/LICENSE-APACHE
+    https://github.com/dtolnay/proc-macro2/blob/1.0.101/LICENSE-MIT
Signature · 1 line
2.52.0
author maintainer
#10 lore raw

PATCH v2 10/20 rust: proc-macro2: enable support in kbuild

In reply to Miguel Ojeda

With all the new files in place and ready from the new crate, enable the support for it in the build system.

proc_macro_byte_character and proc_macro_c_str_literals were stabilized in Rust 1.79.0 [1] and were implemented earlier than our minimum Rust version (1.78) [2][3]. Thus just enable them instead of using the cfg that proc-macro2 uses to emulate them in older compilers.

In addition, skip formatting for this vendored crate and take the chance to add a comment mentioning this.

---
 Makefile                          |  5 +++++
 rust/Makefile                     | 32 +++++++++++++++++++++++++++++--
 scripts/generate_rust_analyzer.py |  7 +++++++
 3 files changed, 42 insertions(+), 2 deletions(-)
Makefile +5 -0
index d14824792227..589bcfe3bf75 100644
@@ -1826,10 +1826,15 @@ rusttest: prepare
 	$(Q)$(MAKE) $(build)=rust $@
 
 # Formatting targets
+#
+# Generated files as well as vendored crates are skipped.
 PHONY += rustfmt rustfmtcheck
 
 rustfmt:
 	$(Q)find $(srctree) $(RCS_FIND_IGNORE) \
+		\( \
+			-path $(srctree)/rust/proc-macro2 \
+		\) -prune -o \
 		-type f -a -name '*.rs' -a ! -name '*generated*' -print \
 		| xargs $(RUSTFMT) $(rustfmt_flags)
 
rust/Makefile +30 -2
index 0288ca8d270c..7dd1261ad98f 100644
@@ -27,6 +27,8 @@ endif
 
 obj-$(CONFIG_RUST) += exports.o
 
+always-$(CONFIG_RUST) += libproc_macro2.rlib
+
 always-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated.rs
 always-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated_kunit.c
 
@@ -76,6 +78,17 @@ core-flags := \
     --edition=$(core-edition) \
     $(call cfgs-to-flags,$(core-cfgs))
 
+proc_macro2-cfgs := \
+    feature="proc-macro" \
+    wrap_proc_macro \
+    $(if $(call rustc-min-version,108800),proc_macro_span_file proc_macro_span_location)
+
+# Stable since Rust 1.79.0: `feature(proc_macro_byte_character,proc_macro_c_str_literals)`.
+proc_macro2-flags := \
+    --cap-lints=allow \
+    -Zcrate-attr='feature(proc_macro_byte_character,proc_macro_c_str_literals)' \
+    $(call cfgs-to-flags,$(proc_macro2-cfgs))
+
 # `rustdoc` did not save the target modifiers, thus workaround for
 # the time being (https://github.com/rust-lang/rust/issues/144521).
 rustdoc_modifiers_workaround := $(if $(call rustc-min-version,108800),-Cunsafe-allow-abi-mismatch=fixed-x18)
@@ -125,10 +138,15 @@ rustdoc: rustdoc-core rustdoc-macros rustdoc-compiler_builtins \
 	$(Q)for f in $(rustdoc_output)/static.files/rustdoc-*.css; do \
 		echo ".logo-container > img { object-fit: contain; }" >> $$f; done
 
+rustdoc-proc_macro2: private rustdoc_host = yes
+rustdoc-proc_macro2: private rustc_target_flags = $(proc_macro2-flags)
+rustdoc-proc_macro2: $(src)/proc-macro2/lib.rs rustdoc-clean FORCE
+	+$(call if_changed,rustdoc)
+
 rustdoc-macros: private rustdoc_host = yes
 rustdoc-macros: private rustc_target_flags = --crate-type proc-macro \
     --extern proc_macro
-rustdoc-macros: $(src)/macros/lib.rs rustdoc-clean FORCE
+rustdoc-macros: $(src)/macros/lib.rs rustdoc-clean rustdoc-proc_macro2 FORCE
 	+$(call if_changed,rustdoc)
 
 # Starting with Rust 1.82.0, skipping `-Wrustdoc::unescaped_backticks` should
@@ -185,6 +203,10 @@ rusttestlib-build_error: $(src)/build_error.rs FORCE
 rusttestlib-ffi: $(src)/ffi.rs FORCE
 	+$(call if_changed,rustc_test_library)
 
+rusttestlib-proc_macro2: private rustc_target_flags = $(proc_macro2-flags)
+rusttestlib-proc_macro2: $(src)/proc-macro2/lib.rs FORCE
+	+$(call if_changed,rustc_test_library)
+
 rusttestlib-macros: private rustc_target_flags = --extern proc_macro
 rusttestlib-macros: private rustc_test_library_proc = yes
 rusttestlib-macros: $(src)/macros/lib.rs FORCE
@@ -431,6 +453,11 @@ quiet_cmd_rustc_procmacrolibrary = $(RUSTC_OR_CLIPPY_QUIET) PL $@
 	mv $(objtree)/$(obj)/$(patsubst lib%.rlib,%,$(notdir $@)).d $(depfile); \
 	sed -i '/^\#/d' $(depfile)
 
+$(obj)/libproc_macro2.rlib: private skip_clippy = 1
+$(obj)/libproc_macro2.rlib: private rustc_target_flags = $(proc_macro2-flags)
+$(obj)/libproc_macro2.rlib: $(src)/proc-macro2/lib.rs FORCE
+	+$(call if_changed_dep,rustc_procmacrolibrary)
+
 quiet_cmd_rustc_procmacro = $(RUSTC_OR_CLIPPY_QUIET) P $@
       cmd_rustc_procmacro = \
 	$(RUSTC_OR_CLIPPY) $(rust_common_flags) $(rustc_target_flags) \
@@ -442,7 +469,7 @@ quiet_cmd_rustc_procmacro = $(RUSTC_OR_CLIPPY_QUIET) P $@
 		@$(objtree)/include/generated/rustc_cfg $<
 
 # Procedural macros can only be used with the `rustc` that compiled it.
-$(obj)/$(libmacros_name): $(src)/macros/lib.rs FORCE
+$(obj)/$(libmacros_name): $(src)/macros/lib.rs $(obj)/libproc_macro2.rlib FORCE
 	+$(call if_changed_dep,rustc_procmacro)
 
 $(obj)/$(libpin_init_internal_name): private rustc_target_flags = --cfg kernel
@@ -465,6 +492,7 @@ quiet_cmd_rustc_library = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET)) L
 rust-analyzer:
 	$(Q)MAKEFLAGS= $(srctree)/scripts/generate_rust_analyzer.py \
 		--cfgs='core=$(core-cfgs)' $(core-edition) \
+		--cfgs='proc_macro2=$(proc_macro2-cfgs)' \
 		$(realpath $(srctree)) $(realpath $(objtree)) \
 		$(rustc_sysroot) $(RUST_LIB_SRC) $(if $(KBUILD_EXTMOD),$(srcroot)) \
 		> rust-project.json
scripts/generate_rust_analyzer.py +7 -0
index dedca470adc1..00c6b7cc94b7 100755
@@ -86,6 +86,13 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edit
         [],
     )
 
+    append_crate(
+        "proc_macro2",
+        srctree / "rust" / "proc-macro2" / "lib.rs",
+        ["core", "alloc", "std", "proc_macro"],
+        cfg=crates_cfgs["proc_macro2"],
+    )
+
     append_crate(
         "macros",
         srctree / "rust" / "macros" / "lib.rs",
Signature · 1 line
2.52.0
author maintainer
#11 lore raw

PATCH v2 11/20 rust: quote: import crate

In reply to Miguel Ojeda

This is a subset of the Rust quote crate, version 1.0.40 (released 2025-03-12), licensed under "Apache-2.0 OR MIT", from:

    https://github.com/dtolnay/quote/raw/1.0.40/src

The files are copied as-is, with no modifications whatsoever (not even adding the SPDX identifiers).

For copyright details, please see:

    https://github.com/dtolnay/quote/blob/1.0.40/README.md#license
    https://github.com/dtolnay/quote/blob/1.0.40/LICENSE-APACHE
    https://github.com/dtolnay/quote/blob/1.0.40/LICENSE-MIT

The next patch modifies these files as needed for use within the kernel. This patch split allows reviewers to double-check the import and to clearly see the differences introduced.

The following script may be used to verify the contents:

    for path in $(cd rust/quote/ && find . -type f -name '*.rs'); do
        curl --silent --show-error --location \
            https://github.com/dtolnay/quote/raw/1.0.40/src/$path \
            | diff --unified rust/quote/$path - && echo $path: OK
    done
---
 rust/quote/ext.rs            |  110 +++
 rust/quote/format.rs         |  168 ++++
 rust/quote/ident_fragment.rs |   88 ++
 rust/quote/lib.rs            | 1454 ++++++++++++++++++++++++++++++++++
 rust/quote/runtime.rs        |  492 ++++++++++++
 rust/quote/spanned.rs        |   50 ++
 rust/quote/to_tokens.rs      |  271 +++++++
 7 files changed, 2633 insertions(+)
 create mode 100644 rust/quote/ext.rs
 create mode 100644 rust/quote/format.rs
 create mode 100644 rust/quote/ident_fragment.rs
 create mode 100644 rust/quote/lib.rs
 create mode 100644 rust/quote/runtime.rs
 create mode 100644 rust/quote/spanned.rs
 create mode 100644 rust/quote/to_tokens.rs
rust/quote/ext.rs new file +110 -0
new file mode 100644
index 000000000000..92c2315b182d
@@ -0,0 +1,110 @@
+use super::ToTokens;
+use core::iter;
+use proc_macro2::{TokenStream, TokenTree};
+
+/// TokenStream extension trait with methods for appending tokens.
+///
+/// This trait is sealed and cannot be implemented outside of the `quote` crate.
+pub trait TokenStreamExt: private::Sealed {
+    /// For use by `ToTokens` implementations.
+    ///
+    /// Appends the token specified to this list of tokens.
+    fn append<U>(&mut self, token: U)
+    where
+        U: Into<TokenTree>;
+
+    /// For use by `ToTokens` implementations.
+    ///
+    /// ```
+    /// # use quote::{quote, TokenStreamExt, ToTokens};
+    /// # use proc_macro2::TokenStream;
+    /// #
+    /// struct X;
+    ///
+    /// impl ToTokens for X {
+    ///     fn to_tokens(&self, tokens: &mut TokenStream) {
+    ///         tokens.append_all(&[true, false]);
+    ///     }
+    /// }
+    ///
+    /// let tokens = quote!(#X);
+    /// assert_eq!(tokens.to_string(), "true false");
+    /// ```
+    fn append_all<I>(&mut self, iter: I)
+    where
+        I: IntoIterator,
+        I::Item: ToTokens;
+
+    /// For use by `ToTokens` implementations.
+    ///
+    /// Appends all of the items in the iterator `I`, separated by the tokens
+    /// `U`.
+    fn append_separated<I, U>(&mut self, iter: I, op: U)
+    where
+        I: IntoIterator,
+        I::Item: ToTokens,
+        U: ToTokens;
+
+    /// For use by `ToTokens` implementations.
+    ///
+    /// Appends all tokens in the iterator `I`, appending `U` after each
+    /// element, including after the last element of the iterator.
+    fn append_terminated<I, U>(&mut self, iter: I, term: U)
+    where
+        I: IntoIterator,
+        I::Item: ToTokens,
+        U: ToTokens;
+}
+
+impl TokenStreamExt for TokenStream {
+    fn append<U>(&mut self, token: U)
+    where
+        U: Into<TokenTree>,
+    {
+        self.extend(iter::once(token.into()));
+    }
+
+    fn append_all<I>(&mut self, iter: I)
+    where
+        I: IntoIterator,
+        I::Item: ToTokens,
+    {
+        for token in iter {
+            token.to_tokens(self);
+        }
+    }
+
+    fn append_separated<I, U>(&mut self, iter: I, op: U)
+    where
+        I: IntoIterator,
+        I::Item: ToTokens,
+        U: ToTokens,
+    {
+        for (i, token) in iter.into_iter().enumerate() {
+            if i > 0 {
+                op.to_tokens(self);
+            }
+            token.to_tokens(self);
+        }
+    }
+
+    fn append_terminated<I, U>(&mut self, iter: I, term: U)
+    where
+        I: IntoIterator,
+        I::Item: ToTokens,
+        U: ToTokens,
+    {
+        for token in iter {
+            token.to_tokens(self);
+            term.to_tokens(self);
+        }
+    }
+}
+
+mod private {
+    use proc_macro2::TokenStream;
+
+    pub trait Sealed {}
+
+    impl Sealed for TokenStream {}
+}
rust/quote/format.rs new file +168 -0

168 lines not on this page · raw message

rust/quote/ident_fragment.rs new file +88 -0

88 lines not on this page · raw message

rust/quote/lib.rs new file +1454 -0

1,454 lines not on this page · raw message

rust/quote/runtime.rs new file +492 -0

492 lines not on this page · raw message

rust/quote/spanned.rs new file +50 -0

50 lines not on this page · raw message

rust/quote/to_tokens.rs new file +271 -0

271 lines not on this page · raw message

Signature · 1 line
2.52.0
author maintainer
#12 lore raw

PATCH v2 12/20 rust: quote: add SPDX License Identifiers

In reply to Miguel Ojeda

Originally, when the Rust upstream alloc standard library crate was vendored in commit 057b8d257107 ("rust: adapt alloc crate to the kernel"), the SPDX License Identifiers were added to every file so that the license on those was clear.

Thus do the same for the quote crate.

This makes scripts/spdxcheck.py pass.

---
 rust/quote/ext.rs            | 2 ++
 rust/quote/format.rs         | 2 ++
 rust/quote/ident_fragment.rs | 2 ++
 rust/quote/lib.rs            | 2 ++
 rust/quote/runtime.rs        | 2 ++
 rust/quote/spanned.rs        | 2 ++
 rust/quote/to_tokens.rs      | 2 ++
 7 files changed, 14 insertions(+)
rust/quote/ext.rs +2 -0
index 92c2315b182d..977d2f0c5919 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 use super::ToTokens;
 use core::iter;
 use proc_macro2::{TokenStream, TokenTree};
rust/quote/format.rs +2 -0
index ec0bbf38ba37..6e3d55b6e427 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 /// Formatting macro for constructing `Ident`s.
 ///
 /// <br>
rust/quote/ident_fragment.rs +2 -0
index 6c2a9a87acb4..d98106f17666 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 use alloc::borrow::Cow;
 use core::fmt;
 use proc_macro2::{Ident, Span};
rust/quote/lib.rs +2 -0
index 0a12d607f279..cc1637660a75 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 //! [![github]](https://github.com/dtolnay/quote)&ensp;[![crates-io]](https://crates.io/crates/quote)&ensp;[![docs-rs]](https://docs.rs/quote)
 //!
 //! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
rust/quote/runtime.rs +2 -0
index c704ca89411f..09a94f5dd4fe 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 use self::get_span::{GetSpan, GetSpanBase, GetSpanInner};
 use crate::{IdentFragment, ToTokens, TokenStreamExt};
 use core::fmt;
rust/quote/spanned.rs +2 -0
index 6eba64445d89..54ce9177f45e 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 use crate::ToTokens;
 use proc_macro2::extra::DelimSpan;
 use proc_macro2::{Span, TokenStream};
rust/quote/to_tokens.rs +2 -0
index f373092b650f..1af1089e1423 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 use super::TokenStreamExt;
 use alloc::borrow::Cow;
 use alloc::rc::Rc;
Signature · 1 line
2.52.0
author maintainer
#13 lore raw

PATCH v2 13/20 rust: quote: add `README.md`

In reply to Miguel Ojeda

Originally, when the Rust upstream alloc standard library crate was vendored in commit 057b8d257107 ("rust: adapt alloc crate to the kernel"), a README.md file was added to explain the provenance and licensing of the source files.

Thus do the same for the quote crate.

---
 rust/quote/README.md | 12 ++++++++++++
 1 file changed, 12 insertions(+)
 create mode 100644 rust/quote/README.md
rust/quote/README.md new file +12 -0
new file mode 100644
index 000000000000..186123eff1cb
@@ -0,0 +1,12 @@
+# `quote`
+
+These source files come from the Rust `quote` crate, version 1.0.40
+(released 2025-03-12), hosted in the <https://github.com/dtolnay/quote>
+repository, licensed under "Apache-2.0 OR MIT" and only modified to add
+the SPDX license identifiers.
+
+For copyright details, please see:
+
+    https://github.com/dtolnay/quote/blob/1.0.40/README.md#license
+    https://github.com/dtolnay/quote/blob/1.0.40/LICENSE-APACHE
+    https://github.com/dtolnay/quote/blob/1.0.40/LICENSE-MIT
Signature · 1 line
2.52.0
author maintainer
#14 lore raw

PATCH v2 14/20 rust: quote: enable support in kbuild

In reply to Miguel Ojeda

With all the new files in place and ready from the new crate, enable the support for it in the build system.

---
 Makefile                          |  1 +
 rust/Makefile                     | 38 ++++++++++++++++++++++++++++---
 scripts/generate_rust_analyzer.py |  7 ++++++
 3 files changed, 43 insertions(+), 3 deletions(-)
Makefile +1 -0
index 589bcfe3bf75..85da055e4f00 100644
@@ -1834,6 +1834,7 @@ rustfmt:
 	$(Q)find $(srctree) $(RCS_FIND_IGNORE) \
 		\( \
 			-path $(srctree)/rust/proc-macro2 \
+			-o -path $(srctree)/rust/quote \
 		\) -prune -o \
 		-type f -a -name '*.rs' -a ! -name '*generated*' -print \
 		| xargs $(RUSTFMT) $(rustfmt_flags)
rust/Makefile +35 -3
index 7dd1261ad98f..4f4a00594142 100644
@@ -27,7 +27,7 @@ endif
 
 obj-$(CONFIG_RUST) += exports.o
 
-always-$(CONFIG_RUST) += libproc_macro2.rlib
+always-$(CONFIG_RUST) += libproc_macro2.rlib libquote.rlib
 
 always-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated.rs
 always-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated_kunit.c
@@ -89,6 +89,18 @@ proc_macro2-flags := \
     -Zcrate-attr='feature(proc_macro_byte_character,proc_macro_c_str_literals)' \
     $(call cfgs-to-flags,$(proc_macro2-cfgs))
 
+quote-cfgs := \
+    feature="proc-macro"
+
+quote-skip_flags := \
+    --edition=2021
+
+quote-flags := \
+    --edition=2018 \
+    --cap-lints=allow \
+    --extern proc_macro2 \
+    $(call cfgs-to-flags,$(quote-cfgs))
+
 # `rustdoc` did not save the target modifiers, thus workaround for
 # the time being (https://github.com/rust-lang/rust/issues/144521).
 rustdoc_modifiers_workaround := $(if $(call rustc-min-version,108800),-Cunsafe-allow-abi-mismatch=fixed-x18)
@@ -143,10 +155,17 @@ rustdoc-proc_macro2: private rustc_target_flags = $(proc_macro2-flags)
 rustdoc-proc_macro2: $(src)/proc-macro2/lib.rs rustdoc-clean FORCE
 	+$(call if_changed,rustdoc)
 
+rustdoc-quote: private rustdoc_host = yes
+rustdoc-quote: private rustc_target_flags = $(quote-flags)
+rustdoc-quote: private skip_flags = $(quote-skip_flags)
+rustdoc-quote: $(src)/quote/lib.rs rustdoc-clean rustdoc-proc_macro2 FORCE
+	+$(call if_changed,rustdoc)
+
 rustdoc-macros: private rustdoc_host = yes
 rustdoc-macros: private rustc_target_flags = --crate-type proc-macro \
     --extern proc_macro
-rustdoc-macros: $(src)/macros/lib.rs rustdoc-clean rustdoc-proc_macro2 FORCE
+rustdoc-macros: $(src)/macros/lib.rs rustdoc-clean rustdoc-proc_macro2 \
+    rustdoc-quote FORCE
 	+$(call if_changed,rustdoc)
 
 # Starting with Rust 1.82.0, skipping `-Wrustdoc::unescaped_backticks` should
@@ -207,6 +226,11 @@ rusttestlib-proc_macro2: private rustc_target_flags = $(proc_macro2-flags)
 rusttestlib-proc_macro2: $(src)/proc-macro2/lib.rs FORCE
 	+$(call if_changed,rustc_test_library)
 
+rusttestlib-quote: private skip_flags = $(quote-skip_flags)
+rusttestlib-quote: private rustc_target_flags = $(quote-flags)
+rusttestlib-quote: $(src)/quote/lib.rs rusttestlib-proc_macro2 FORCE
+	+$(call if_changed,rustc_test_library)
+
 rusttestlib-macros: private rustc_target_flags = --extern proc_macro
 rusttestlib-macros: private rustc_test_library_proc = yes
 rusttestlib-macros: $(src)/macros/lib.rs FORCE
@@ -458,6 +482,12 @@ $(obj)/libproc_macro2.rlib: private rustc_target_flags = $(proc_macro2-flags)
 $(obj)/libproc_macro2.rlib: $(src)/proc-macro2/lib.rs FORCE
 	+$(call if_changed_dep,rustc_procmacrolibrary)
 
+$(obj)/libquote.rlib: private skip_clippy = 1
+$(obj)/libquote.rlib: private skip_flags = $(quote-skip_flags)
+$(obj)/libquote.rlib: private rustc_target_flags = $(quote-flags)
+$(obj)/libquote.rlib: $(src)/quote/lib.rs $(obj)/libproc_macro2.rlib FORCE
+	+$(call if_changed_dep,rustc_procmacrolibrary)
+
 quiet_cmd_rustc_procmacro = $(RUSTC_OR_CLIPPY_QUIET) P $@
       cmd_rustc_procmacro = \
 	$(RUSTC_OR_CLIPPY) $(rust_common_flags) $(rustc_target_flags) \
@@ -469,7 +499,8 @@ quiet_cmd_rustc_procmacro = $(RUSTC_OR_CLIPPY_QUIET) P $@
 		@$(objtree)/include/generated/rustc_cfg $<
 
 # Procedural macros can only be used with the `rustc` that compiled it.
-$(obj)/$(libmacros_name): $(src)/macros/lib.rs $(obj)/libproc_macro2.rlib FORCE
+$(obj)/$(libmacros_name): $(src)/macros/lib.rs $(obj)/libproc_macro2.rlib \
+    $(obj)/libquote.rlib FORCE
 	+$(call if_changed_dep,rustc_procmacro)
 
 $(obj)/$(libpin_init_internal_name): private rustc_target_flags = --cfg kernel
@@ -493,6 +524,7 @@ rust-analyzer:
 	$(Q)MAKEFLAGS= $(srctree)/scripts/generate_rust_analyzer.py \
 		--cfgs='core=$(core-cfgs)' $(core-edition) \
 		--cfgs='proc_macro2=$(proc_macro2-cfgs)' \
+		--cfgs='quote=$(quote-cfgs)' \
 		$(realpath $(srctree)) $(realpath $(objtree)) \
 		$(rustc_sysroot) $(RUST_LIB_SRC) $(if $(KBUILD_EXTMOD),$(srcroot)) \
 		> rust-project.json
scripts/generate_rust_analyzer.py +7 -0
index 00c6b7cc94b7..4faf153ed2ee 100755
@@ -93,6 +93,13 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edit
         cfg=crates_cfgs["proc_macro2"],
     )
 
+    append_crate(
+        "quote",
+        srctree / "rust" / "quote" / "lib.rs",
+        ["alloc", "proc_macro", "proc_macro2"],
+        cfg=crates_cfgs["quote"],
+    )
+
     append_crate(
         "macros",
         srctree / "rust" / "macros" / "lib.rs",
Signature · 1 line
2.52.0
author maintainer
#15 lore raw

PATCH v2 15/20 rust: syn: import crate

In reply to Miguel Ojeda

This is a subset of the Rust syn crate, version 2.0.106 (released 2025-08-16), licensed under "Apache-2.0 OR MIT", from:

    https://github.com/dtolnay/syn/raw/2.0.106/src

The files are copied as-is, with no modifications whatsoever (not even adding the SPDX identifiers).

For copyright details, please see:

    https://github.com/dtolnay/syn/blob/2.0.106/README.md#license
    https://github.com/dtolnay/syn/blob/2.0.106/LICENSE-APACHE
    https://github.com/dtolnay/syn/blob/2.0.106/LICENSE-MIT

The next two patches modify these files as needed for use within the kernel. This patch split allows reviewers to double-check the import and to clearly see the differences introduced.

The following script may be used to verify the contents:

    for path in $(cd rust/syn/ && find . -type f -name '*.rs'); do
        curl --silent --show-error --location \
            https://github.com/dtolnay/syn/raw/2.0.106/src/$path \
            | diff --unified rust/syn/$path - && echo $path: OK
    done
---
 rust/syn/attr.rs               |  836 +++++++
 rust/syn/bigint.rs             |   66 +
 rust/syn/buffer.rs             |  434 ++++
 rust/syn/classify.rs           |  311 +++
 rust/syn/custom_keyword.rs     |  260 ++
 rust/syn/custom_punctuation.rs |  304 +++
 rust/syn/data.rs               |  424 ++++
 rust/syn/derive.rs             |  259 ++
 rust/syn/discouraged.rs        |  225 ++
 rust/syn/drops.rs              |   58 +
 rust/syn/error.rs              |  467 ++++
 rust/syn/export.rs             |   73 +
 rust/syn/expr.rs               | 4173 ++++++++++++++++++++++++++++++++
 rust/syn/ext.rs                |  136 ++
 rust/syn/file.rs               |  125 +
 rust/syn/fixup.rs              |  773 ++++++
 rust/syn/gen/clone.rs          | 2267 +++++++++++++++++
 rust/syn/gen/debug.rs          | 3238 +++++++++++++++++++++++++
 rust/syn/gen/eq.rs             | 2306 ++++++++++++++++++
 rust/syn/gen/fold.rs           | 3902 +++++++++++++++++++++++++++++
 rust/syn/gen/hash.rs           | 2876 ++++++++++++++++++++++
 rust/syn/gen/visit.rs          | 3941 ++++++++++++++++++++++++++++++
 rust/syn/gen/visit_mut.rs      | 3759 ++++++++++++++++++++++++++++
 rust/syn/generics.rs           | 1477 +++++++++++
 rust/syn/group.rs              |  291 +++
 rust/syn/ident.rs              |  108 +
 rust/syn/item.rs               | 3490 ++++++++++++++++++++++++++
 rust/syn/lib.rs                | 1011 ++++++++
 rust/syn/lifetime.rs           |  156 ++
 rust/syn/lit.rs                | 1860 ++++++++++++++
 rust/syn/lookahead.rs          |  332 +++
 rust/syn/mac.rs                |  225 ++
 rust/syn/macros.rs             |  182 ++
 rust/syn/meta.rs               |  427 ++++
 rust/syn/op.rs                 |  219 ++
 rust/syn/parse.rs              | 1419 +++++++++++
 rust/syn/parse_macro_input.rs  |  128 +
 rust/syn/parse_quote.rs        |  240 ++
 rust/syn/pat.rs                |  955 ++++++++
 rust/syn/path.rs               |  966 ++++++++
 rust/syn/precedence.rs         |  210 ++
 rust/syn/print.rs              |   16 +
 rust/syn/punctuated.rs         | 1155 +++++++++
 rust/syn/restriction.rs        |  178 ++
 rust/syn/scan_expr.rs          |  265 ++
 rust/syn/sealed.rs             |    4 +
 rust/syn/span.rs               |   63 +
 rust/syn/spanned.rs            |  118 +
 rust/syn/stmt.rs               |  484 ++++
 rust/syn/thread.rs             |   60 +
 rust/syn/token.rs              | 1096 +++++++++
 rust/syn/tt.rs                 |  107 +
 rust/syn/ty.rs                 | 1271 ++++++++++
 rust/syn/verbatim.rs           |   33 +
 rust/syn/whitespace.rs         |   65 +
 55 files changed, 49824 insertions(+)
 create mode 100644 rust/syn/attr.rs
 create mode 100644 rust/syn/bigint.rs
 create mode 100644 rust/syn/buffer.rs
 create mode 100644 rust/syn/classify.rs
 create mode 100644 rust/syn/custom_keyword.rs
 create mode 100644 rust/syn/custom_punctuation.rs
 create mode 100644 rust/syn/data.rs
 create mode 100644 rust/syn/derive.rs
 create mode 100644 rust/syn/discouraged.rs
 create mode 100644 rust/syn/drops.rs
 create mode 100644 rust/syn/error.rs
 create mode 100644 rust/syn/export.rs
 create mode 100644 rust/syn/expr.rs
 create mode 100644 rust/syn/ext.rs
 create mode 100644 rust/syn/file.rs
 create mode 100644 rust/syn/fixup.rs
 create mode 100644 rust/syn/gen/clone.rs
 create mode 100644 rust/syn/gen/debug.rs
 create mode 100644 rust/syn/gen/eq.rs
 create mode 100644 rust/syn/gen/fold.rs
 create mode 100644 rust/syn/gen/hash.rs
 create mode 100644 rust/syn/gen/visit.rs
 create mode 100644 rust/syn/gen/visit_mut.rs
 create mode 100644 rust/syn/generics.rs
 create mode 100644 rust/syn/group.rs
 create mode 100644 rust/syn/ident.rs
 create mode 100644 rust/syn/item.rs
 create mode 100644 rust/syn/lib.rs
 create mode 100644 rust/syn/lifetime.rs
 create mode 100644 rust/syn/lit.rs
 create mode 100644 rust/syn/lookahead.rs
 create mode 100644 rust/syn/mac.rs
 create mode 100644 rust/syn/macros.rs
 create mode 100644 rust/syn/meta.rs
 create mode 100644 rust/syn/op.rs
 create mode 100644 rust/syn/parse.rs
 create mode 100644 rust/syn/parse_macro_input.rs
 create mode 100644 rust/syn/parse_quote.rs
 create mode 100644 rust/syn/pat.rs
 create mode 100644 rust/syn/path.rs
 create mode 100644 rust/syn/precedence.rs
 create mode 100644 rust/syn/print.rs
 create mode 100644 rust/syn/punctuated.rs
 create mode 100644 rust/syn/restriction.rs
 create mode 100644 rust/syn/scan_expr.rs
 create mode 100644 rust/syn/sealed.rs
 create mode 100644 rust/syn/span.rs
 create mode 100644 rust/syn/spanned.rs
 create mode 100644 rust/syn/stmt.rs
 create mode 100644 rust/syn/thread.rs
 create mode 100644 rust/syn/token.rs
 create mode 100644 rust/syn/tt.rs
 create mode 100644 rust/syn/ty.rs
 create mode 100644 rust/syn/verbatim.rs
 create mode 100644 rust/syn/whitespace.rs
rust/syn/attr.rs new file +836 -0
new file mode 100644
index 000000000000..2bdf96ee7fa9
@@ -0,0 +1,836 @@
+#[cfg(feature = "parsing")]
+use crate::error::Error;
+#[cfg(feature = "parsing")]
+use crate::error::Result;
+use crate::expr::Expr;
+use crate::mac::MacroDelimiter;
+#[cfg(feature = "parsing")]
+use crate::meta::{self, ParseNestedMeta};
+#[cfg(feature = "parsing")]
+use crate::parse::{Parse, ParseStream, Parser};
+use crate::path::Path;
+use crate::token;
+use proc_macro2::TokenStream;
+#[cfg(feature = "printing")]
+use std::iter;
+#[cfg(feature = "printing")]
+use std::slice;
+
+ast_struct! {
+    /// An attribute, like `#[repr(transparent)]`.
+    ///
+    /// <br>
+    ///
+    /// # Syntax
+    ///
+    /// Rust has six types of attributes.
+    ///
+    /// - Outer attributes like `#[repr(transparent)]`. These appear outside or
+    ///   in front of the item they describe.
+    ///
+    /// - Inner attributes like `#![feature(proc_macro)]`. These appear inside
+    ///   of the item they describe, usually a module.
+    ///
+    /// - Outer one-line doc comments like `/// Example`.
+    ///
+    /// - Inner one-line doc comments like `//! Please file an issue`.
+    ///
+    /// - Outer documentation blocks `/** Example */`.
+    ///
+    /// - Inner documentation blocks `/*! Please file an issue */`.
+    ///
+    /// The `style` field of type `AttrStyle` distinguishes whether an attribute
+    /// is outer or inner.
+    ///
+    /// Every attribute has a `path` that indicates the intended interpretation
+    /// of the rest of the attribute's contents. The path and the optional
+    /// additional contents are represented together in the `meta` field of the
+    /// attribute in three possible varieties:
+    ///
+    /// - Meta::Path &mdash; attributes whose information content conveys just a
+    ///   path, for example the `#[test]` attribute.
+    ///
+    /// - Meta::List &mdash; attributes that carry arbitrary tokens after the
+    ///   path, surrounded by a delimiter (parenthesis, bracket, or brace). For
+    ///   example `#[derive(Copy)]` or `#[precondition(x < 5)]`.
+    ///
+    /// - Meta::NameValue &mdash; attributes with an `=` sign after the path,
+    ///   followed by a Rust expression. For example `#[path =
+    ///   "sys/windows.rs"]`.
+    ///
+    /// All doc comments are represented in the NameValue style with a path of
+    /// "doc", as this is how they are processed by the compiler and by
+    /// `macro_rules!` macros.
+    ///
+    /// ```text
+    /// #[derive(Copy, Clone)]
+    ///   ~~~~~~Path
+    ///   ^^^^^^^^^^^^^^^^^^^Meta::List
+    ///
+    /// #[path = "sys/windows.rs"]
+    ///   ~~~~Path
+    ///   ^^^^^^^^^^^^^^^^^^^^^^^Meta::NameValue
+    ///
+    /// #[test]
+    ///   ^^^^Meta::Path
+    /// ```
+    ///
+    /// <br>
+    ///
+    /// # Parsing from tokens to Attribute
+    ///
+    /// This type does not implement the [`Parse`] trait and thus cannot be
+    /// parsed directly by [`ParseStream::parse`]. Instead use
+    /// [`ParseStream::call`] with one of the two parser functions
+    /// [`Attribute::parse_outer`] or [`Attribute::parse_inner`] depending on
+    /// which you intend to parse.
+    ///
+    /// [`Parse`]: crate::parse::Parse
+    /// [`ParseStream::parse`]: crate::parse::ParseBuffer::parse
+    /// [`ParseStream::call`]: crate::parse::ParseBuffer::call
+    ///
+    /// ```
+    /// use syn::{Attribute, Ident, Result, Token};
+    /// use syn::parse::{Parse, ParseStream};
+    ///
+    /// // Parses a unit struct with attributes.
+    /// //
+    /// //     #[path = "s.tmpl"]
+    /// //     struct S;
+    /// struct UnitStruct {
+    ///     attrs: Vec<Attribute>,
+    ///     struct_token: Token![struct],
+    ///     name: Ident,
+    ///     semi_token: Token![;],
+    /// }
+    ///
+    /// impl Parse for UnitStruct {
+    ///     fn parse(input: ParseStream) -> Result<Self> {
+    ///         Ok(UnitStruct {
+    ///             attrs: input.call(Attribute::parse_outer)?,
+    ///             struct_token: input.parse()?,
+    ///             name: input.parse()?,
+    ///             semi_token: input.parse()?,
+    ///         })
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// <p><br></p>
+    ///
+    /// # Parsing from Attribute to structured arguments
+    ///
+    /// The grammar of attributes in Rust is very flexible, which makes the
+    /// syntax tree not that useful on its own. In particular, arguments of the
+    /// `Meta::List` variety of attribute are held in an arbitrary `tokens:
+    /// TokenStream`. Macros are expected to check the `path` of the attribute,
+    /// decide whether they recognize it, and then parse the remaining tokens
+    /// according to whatever grammar they wish to require for that kind of
+    /// attribute. Use [`parse_args()`] to parse those tokens into the expected
+    /// data structure.
+    ///
+    /// [`parse_args()`]: Attribute::parse_args
+    ///
+    /// <p><br></p>
+    ///
+    /// # Doc comments
+    ///
+    /// The compiler transforms doc comments, such as `/// comment` and `/*!
+    /// comment */`, into attributes before macros are expanded. Each comment is
+    /// expanded into an attribute of the form `#[doc = r"comment"]`.
+    ///
+    /// As an example, the following `mod` items are expanded identically:
+    ///
+    /// ```
+    /// # use syn::{ItemMod, parse_quote};
+    /// let doc: ItemMod = parse_quote! {
+    ///     /// Single line doc comments
+    ///     /// We write so many!
+    ///     /**
+    ///      * Multi-line comments...
+    ///      * May span many lines
+    ///      */
+    ///     mod example {
+    ///         //! Of course, they can be inner too
+    ///         /*! And fit in a single line */
+    ///     }
+    /// };
+    /// let attr: ItemMod = parse_quote! {
+    ///     #[doc = r" Single line doc comments"]
+    ///     #[doc = r" We write so many!"]
+    ///     #[doc = r"
+    ///      * Multi-line comments...
+    ///      * May span many lines
+    ///      "]
+    ///     mod example {
+    ///         #![doc = r" Of course, they can be inner too"]
+    ///         #![doc = r" And fit in a single line "]
+    ///     }
+    /// };
+    /// assert_eq!(doc, attr);
+    /// ```
+    #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
+    pub struct Attribute {
+        pub pound_token: Token![#],
+        pub style: AttrStyle,
+        pub bracket_token: token::Bracket,
+        pub meta: Meta,
+    }
+}
+
+impl Attribute {
+    /// Returns the path that identifies the interpretation of this attribute.
+    ///
+    /// For example this would return the `test` in `#[test]`, the `derive` in
+    /// `#[derive(Copy)]`, and the `path` in `#[path = "sys/windows.rs"]`.
+    pub fn path(&self) -> &Path {
+        self.meta.path()
+    }
+
+    /// Parse the arguments to the attribute as a syntax tree.
+    ///
+    /// This is similar to pulling out the `TokenStream` from `Meta::List` and
+    /// doing `syn::parse2::<T>(meta_list.tokens)`, except that using
+    /// `parse_args` the error message has a more useful span when `tokens` is
+    /// empty.
+    ///
+    /// The surrounding delimiters are *not* included in the input to the
+    /// parser.
+    ///
+    /// ```text
+    /// #[my_attr(value < 5)]
+    ///           ^^^^^^^^^ what gets parsed
+    /// ```
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use syn::{parse_quote, Attribute, Expr};
+    ///
+    /// let attr: Attribute = parse_quote! {
+    ///     #[precondition(value < 5)]
+    /// };
+    ///
+    /// if attr.path().is_ident("precondition") {
+    ///     let precondition: Expr = attr.parse_args()?;
+    ///     // ...
+    /// }
+    /// # anyhow::Ok(())
+    /// ```
+    #[cfg(feature = "parsing")]
+    #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
+    pub fn parse_args<T: Parse>(&self) -> Result<T> {
+        self.parse_args_with(T::parse)
+    }
+
+    /// Parse the arguments to the attribute using the given parser.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use syn::{parse_quote, Attribute};
+    ///
+    /// let attr: Attribute = parse_quote! {
+    ///     #[inception { #[brrrrrrraaaaawwwwrwrrrmrmrmmrmrmmmmm] }]
+    /// };
+    ///
+    /// let bwom = attr.parse_args_with(Attribute::parse_outer)?;
+    ///
+    /// // Attribute does not have a Parse impl, so we couldn't directly do:
+    /// // let bwom: Attribute = attr.parse_args()?;
+    /// # anyhow::Ok(())
+    /// ```
+    #[cfg(feature = "parsing")]
+    #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
+    pub fn parse_args_with<F: Parser>(&self, parser: F) -> Result<F::Output> {
+        match &self.meta {
+            Meta::Path(path) => Err(crate::error::new2(
+                path.segments.first().unwrap().ident.span(),
+                path.segments.last().unwrap().ident.span(),
+                format!(
+                    "expected attribute arguments in parentheses: {}[{}(...)]",
+                    parsing::DisplayAttrStyle(&self.style),
+                    parsing::DisplayPath(path),
+                ),
+            )),
+            Meta::NameValue(meta) => Err(Error::new(
+                meta.eq_token.span,
+                format_args!(
+                    "expected parentheses: {}[{}(...)]",
+                    parsing::DisplayAttrStyle(&self.style),
+                    parsing::DisplayPath(&meta.path),
+                ),
+            )),
+            Meta::List(meta) => meta.parse_args_with(parser),
+        }
+    }
+
+    /// Parse the arguments to the attribute, expecting it to follow the
+    /// conventional structure used by most of Rust's built-in attributes.
+    ///
+    /// The [*Meta Item Attribute Syntax*][syntax] section in the Rust reference
+    /// explains the convention in more detail. Not all attributes follow this
+    /// convention, so [`parse_args()`][Self::parse_args] is available if you
+    /// need to parse arbitrarily goofy attribute syntax.
+    ///
+    /// [syntax]: https://doc.rust-lang.org/reference/attributes.html#meta-item-attribute-syntax
+    ///
+    /// # Example
+    ///
+    /// We'll parse a struct, and then parse some of Rust's `#[repr]` attribute
+    /// syntax.
+    ///
+    /// ```
+    /// use syn::{parenthesized, parse_quote, token, ItemStruct, LitInt};
+    ///
+    /// let input: ItemStruct = parse_quote! {
+    ///     #[repr(C, align(4))]
+    ///     pub struct MyStruct(u16, u32);
+    /// };
+    ///
+    /// let mut repr_c = false;
+    /// let mut repr_transparent = false;
+    /// let mut repr_align = None::<usize>;
+    /// let mut repr_packed = None::<usize>;
+    /// for attr in &input.attrs {
+    ///     if attr.path().is_ident("repr") {
+    ///         attr.parse_nested_meta(|meta| {
+    ///             // #[repr(C)]
+    ///             if meta.path.is_ident("C") {
+    ///                 repr_c = true;
+    ///                 return Ok(());
+    ///             }
+    ///
+    ///             // #[repr(transparent)]
+    ///             if meta.path.is_ident("transparent") {
+    ///                 repr_transparent = true;
+    ///                 return Ok(());
+    ///             }
+    ///
+    ///             // #[repr(align(N))]
+    ///             if meta.path.is_ident("align") {
+    ///                 let content;
+    ///                 parenthesized!(content in meta.input);
+    ///                 let lit: LitInt = content.parse()?;
+    ///                 let n: usize = lit.base10_parse()?;
+    ///                 repr_align = Some(n);
+    ///                 return Ok(());
+    ///             }
+    ///
+    ///             // #[repr(packed)] or #[repr(packed(N))], omitted N means 1
+    ///             if meta.path.is_ident("packed") {
+    ///                 if meta.input.peek(token::Paren) {
+    ///                     let content;
+    ///                     parenthesized!(content in meta.input);
+    ///                     let lit: LitInt = content.parse()?;
+    ///                     let n: usize = lit.base10_parse()?;
+    ///                     repr_packed = Some(n);
+    ///                 } else {
+    ///                     repr_packed = Some(1);
+    ///                 }
+    ///                 return Ok(());
+    ///             }
+    ///
+    ///             Err(meta.error("unrecognized repr"))
+    ///         })?;
+    ///     }
+    /// }
+    /// # anyhow::Ok(())
+    /// ```
+    ///
+    /// # Alternatives
+    ///
+    /// In some cases, for attributes which have nested layers of structured
+    /// content, the following less flexible approach might be more convenient:
+    ///
+    /// ```
+    /// # use syn::{parse_quote, ItemStruct};
+    /// #
+    /// # let input: ItemStruct = parse_quote! {
+    /// #     #[repr(C, align(4))]
+    /// #     pub struct MyStruct(u16, u32);
+    /// # };
+    /// #
+    /// use syn::punctuated::Punctuated;
+    /// use syn::{parenthesized, token, Error, LitInt, Meta, Token};
+    ///
+    /// let mut repr_c = false;
+    /// let mut repr_transparent = false;
+    /// let mut repr_align = None::<usize>;
+    /// let mut repr_packed = None::<usize>;
+    /// for attr in &input.attrs {
+    ///     if attr.path().is_ident("repr") {
+    ///         let nested = attr.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)?;
+    ///         for meta in nested {
+    ///             match meta {
+    ///                 // #[repr(C)]
+    ///                 Meta::Path(path) if path.is_ident("C") => {
+    ///                     repr_c = true;
+    ///                 }
+    ///
+    ///                 // #[repr(align(N))]
+    ///                 Meta::List(meta) if meta.path.is_ident("align") => {
+    ///                     let lit: LitInt = meta.parse_args()?;
+    ///                     let n: usize = lit.base10_parse()?;
+    ///                     repr_align = Some(n);
+    ///                 }
+    ///
+    ///                 /* ... */
+    ///
+    ///                 _ => {
+    ///                     return Err(Error::new_spanned(meta, "unrecognized repr"));
+    ///                 }
+    ///             }
+    ///         }
+    ///     }
+    /// }
+    /// # Ok(())
+    /// ```
+    #[cfg(feature = "parsing")]
+    #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
+    pub fn parse_nested_meta(
+        &self,
+        logic: impl FnMut(ParseNestedMeta) -> Result<()>,
+    ) -> Result<()> {
+        self.parse_args_with(meta::parser(logic))
+    }
+
+    /// Parses zero or more outer attributes from the stream.
+    ///
+    /// # Example
+    ///
+    /// See
+    /// [*Parsing from tokens to Attribute*](#parsing-from-tokens-to-attribute).
+    #[cfg(feature = "parsing")]
+    #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
+    pub fn parse_outer(input: ParseStream) -> Result<Vec<Self>> {
+        let mut attrs = Vec::new();
+        while input.peek(Token![#]) {
+            attrs.push(input.call(parsing::single_parse_outer)?);
+        }
+        Ok(attrs)
+    }
+
+    /// Parses zero or more inner attributes from the stream.
+    ///
+    /// # Example
+    ///
+    /// See
+    /// [*Parsing from tokens to Attribute*](#parsing-from-tokens-to-attribute).
+    #[cfg(feature = "parsing")]
+    #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
+    pub fn parse_inner(input: ParseStream) -> Result<Vec<Self>> {
+        let mut attrs = Vec::new();
+        parsing::parse_inner(input, &mut attrs)?;
+        Ok(attrs)
+    }
+}
+
+ast_enum! {
+    /// Distinguishes between attributes that decorate an item and attributes
+    /// that are contained within an item.
+    ///
+    /// # Outer attributes
+    ///
+    /// - `#[repr(transparent)]`
+    /// - `/// # Example`
+    /// - `/** Please file an issue */`
+    ///
+    /// # Inner attributes
+    ///
+    /// - `#![feature(proc_macro)]`
+    /// - `//! # Example`
+    /// - `/*! Please file an issue */`
+    #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
+    pub enum AttrStyle {
+        Outer,
+        Inner(Token![!]),
+    }
+}
+
+ast_enum! {
+    /// Content of a compile-time structured attribute.
+    ///
+    /// ## Path
+    ///
+    /// A meta path is like the `test` in `#[test]`.
+    ///
+    /// ## List
+    ///
+    /// A meta list is like the `derive(Copy)` in `#[derive(Copy)]`.
+    ///
+    /// ## NameValue
+    ///
+    /// A name-value meta is like the `path = "..."` in `#[path =
+    /// "sys/windows.rs"]`.
+    ///
+    /// # Syntax tree enum
+    ///
+    /// This type is a [syntax tree enum].
+    ///
+    /// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums
+    #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
+    pub enum Meta {
+        Path(Path),
+
+        /// A structured list within an attribute, like `derive(Copy, Clone)`.
+        List(MetaList),
+
+        /// A name-value pair within an attribute, like `feature = "nightly"`.
+        NameValue(MetaNameValue),
+    }
+}
+
+ast_struct! {
+    /// A structured list within an attribute, like `derive(Copy, Clone)`.
+    #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
+    pub struct MetaList {
+        pub path: Path,
+        pub delimiter: MacroDelimiter,
+        pub tokens: TokenStream,
+    }
+}
+
+ast_struct! {
+    /// A name-value pair within an attribute, like `feature = "nightly"`.
+    #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
+    pub struct MetaNameValue {
+        pub path: Path,
+        pub eq_token: Token![=],
+        pub value: Expr,
+    }
+}
+
+impl Meta {
+    /// Returns the path that begins this structured meta item.
+    ///
+    /// For example this would return the `test` in `#[test]`, the `derive` in
+    /// `#[derive(Copy)]`, and the `path` in `#[path = "sys/windows.rs"]`.
+    pub fn path(&self) -> &Path {
+        match self {
+            Meta::Path(path) => path,
+            Meta::List(meta) => &meta.path,
+            Meta::NameValue(meta) => &meta.path,
+        }
+    }
+
+    /// Error if this is a `Meta::List` or `Meta::NameValue`.
+    #[cfg(feature = "parsing")]
+    #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
+    pub fn require_path_only(&self) -> Result<&Path> {
+        let error_span = match self {
+            Meta::Path(path) => return Ok(path),
+            Meta::List(meta) => meta.delimiter.span().open(),
+            Meta::NameValue(meta) => meta.eq_token.span,
+        };
+        Err(Error::new(error_span, "unexpected token in attribute"))
+    }
+
+    /// Error if this is a `Meta::Path` or `Meta::NameValue`.
+    #[cfg(feature = "parsing")]
+    #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
+    pub fn require_list(&self) -> Result<&MetaList> {
+        match self {
+            Meta::List(meta) => Ok(meta),
+            Meta::Path(path) => Err(crate::error::new2(
+                path.segments.first().unwrap().ident.span(),
+                path.segments.last().unwrap().ident.span(),
+                format!(
+                    "expected attribute arguments in parentheses: `{}(...)`",
+                    parsing::DisplayPath(path),
+                ),
+            )),
+            Meta::NameValue(meta) => Err(Error::new(meta.eq_token.span, "expected `(`")),
+        }
+    }
+
+    /// Error if this is a `Meta::Path` or `Meta::List`.
+    #[cfg(feature = "parsing")]
+    #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
+    pub fn require_name_value(&self) -> Result<&MetaNameValue> {
+        match self {
+            Meta::NameValue(meta) => Ok(meta),
+            Meta::Path(path) => Err(crate::error::new2(
+                path.segments.first().unwrap().ident.span(),
+                path.segments.last().unwrap().ident.span(),
+                format!(
+                    "expected a value for this attribute: `{} = ...`",
+                    parsing::DisplayPath(path),
+                ),
+            )),
+            Meta::List(meta) => Err(Error::new(meta.delimiter.span().open(), "expected `=`")),
+        }
+    }
+}
+
+impl MetaList {
+    /// See [`Attribute::parse_args`].
+    #[cfg(feature = "parsing")]
+    #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
+    pub fn parse_args<T: Parse>(&self) -> Result<T> {
+        self.parse_args_with(T::parse)
+    }
+
+    /// See [`Attribute::parse_args_with`].
+    #[cfg(feature = "parsing")]
+    #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
+    pub fn parse_args_with<F: Parser>(&self, parser: F) -> Result<F::Output> {
+        let scope = self.delimiter.span().close();
+        crate::parse::parse_scoped(parser, scope, self.tokens.clone())
+    }
+
+    /// See [`Attribute::parse_nested_meta`].
+    #[cfg(feature = "parsing")]
+    #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
+    pub fn parse_nested_meta(
+        &self,
+        logic: impl FnMut(ParseNestedMeta) -> Result<()>,
+    ) -> Result<()> {
+        self.parse_args_with(meta::parser(logic))
+    }
+}
+
+#[cfg(feature = "printing")]
+pub(crate) trait FilterAttrs<'a> {
+    type Ret: Iterator<Item = &'a Attribute>;
+
+    fn outer(self) -> Self::Ret;
+    #[cfg(feature = "full")]
+    fn inner(self) -> Self::Ret;
+}
+
+#[cfg(feature = "printing")]
+impl<'a> FilterAttrs<'a> for &'a [Attribute] {
+    type Ret = iter::Filter<slice::Iter<'a, Attribute>, fn(&&Attribute) -> bool>;
+
+    fn outer(self) -> Self::Ret {
+        fn is_outer(attr: &&Attribute) -> bool {
+            match attr.style {
+                AttrStyle::Outer => true,
+                AttrStyle::Inner(_) => false,
+            }
+        }
+        self.iter().filter(is_outer)
+    }
+
+    #[cfg(feature = "full")]
+    fn inner(self) -> Self::Ret {
+        fn is_inner(attr: &&Attribute) -> bool {
+            match attr.style {
+                AttrStyle::Inner(_) => true,
+                AttrStyle::Outer => false,
+            }
+        }
+        self.iter().filter(is_inner)
+    }
+}
+
+impl From<Path> for Meta {
+    fn from(meta: Path) -> Meta {
+        Meta::Path(meta)
+    }
+}
+
+impl From<MetaList> for Meta {
+    fn from(meta: MetaList) -> Meta {
+        Meta::List(meta)
+    }
+}
+
+impl From<MetaNameValue> for Meta {
+    fn from(meta: MetaNameValue) -> Meta {
+        Meta::NameValue(meta)
+    }
+}
+
+#[cfg(feature = "parsing")]
+pub(crate) mod parsing {
+    use crate::attr::{AttrStyle, Attribute, Meta, MetaList, MetaNameValue};
+    use crate::error::Result;
+    use crate::expr::{Expr, ExprLit};
+    use crate::lit::Lit;
+    use crate::parse::discouraged::Speculative as _;
+    use crate::parse::{Parse, ParseStream};
+    use crate::path::Path;
+    use crate::{mac, token};
+    use proc_macro2::Ident;
+    use std::fmt::{self, Display};
+
+    pub(crate) fn parse_inner(input: ParseStream, attrs: &mut Vec<Attribute>) -> Result<()> {
+        while input.peek(Token![#]) && input.peek2(Token![!]) {
+            attrs.push(input.call(single_parse_inner)?);
+        }
+        Ok(())
+    }
+
+    pub(crate) fn single_parse_inner(input: ParseStream) -> Result<Attribute> {
+        let content;
+        Ok(Attribute {
+            pound_token: input.parse()?,
+            style: AttrStyle::Inner(input.parse()?),
+            bracket_token: bracketed!(content in input),
+            meta: content.parse()?,
+        })
+    }
+
+    pub(crate) fn single_parse_outer(input: ParseStream) -> Result<Attribute> {
+        let content;
+        Ok(Attribute {
+            pound_token: input.parse()?,
+            style: AttrStyle::Outer,
+            bracket_token: bracketed!(content in input),
+            meta: content.parse()?,
+        })
+    }
+
+    #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
+    impl Parse for Meta {
+        fn parse(input: ParseStream) -> Result<Self> {
+            let path = parse_outermost_meta_path(input)?;
+            parse_meta_after_path(path, input)
+        }
+    }
+
+    #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
+    impl Parse for MetaList {
+        fn parse(input: ParseStream) -> Result<Self> {
+            let path = parse_outermost_meta_path(input)?;
+            parse_meta_list_after_path(path, input)
+        }
+    }
+
+    #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
+    impl Parse for MetaNameValue {
+        fn parse(input: ParseStream) -> Result<Self> {
+            let path = parse_outermost_meta_path(input)?;
+            parse_meta_name_value_after_path(path, input)
+        }
+    }
+
+    // Unlike meta::parse_meta_path which accepts arbitrary keywords in the path,
+    // only the `unsafe` keyword is accepted as an attribute's outermost path.
+    fn parse_outermost_meta_path(input: ParseStream) -> Result<Path> {
+        if input.peek(Token![unsafe]) {
+            let unsafe_token: Token![unsafe] = input.parse()?;
+            Ok(Path::from(Ident::new("unsafe", unsafe_token.span)))
+        } else {
+            Path::parse_mod_style(input)
+        }
+    }
+
+    pub(crate) fn parse_meta_after_path(path: Path, input: ParseStream) -> Result<Meta> {
+        if input.peek(token::Paren) || input.peek(token::Bracket) || input.peek(token::Brace) {
+            parse_meta_list_after_path(path, input).map(Meta::List)
+        } else if input.peek(Token![=]) {
+            parse_meta_name_value_after_path(path, input).map(Meta::NameValue)
+        } else {
+            Ok(Meta::Path(path))
+        }
+    }
+
+    fn parse_meta_list_after_path(path: Path, input: ParseStream) -> Result<MetaList> {
+        let (delimiter, tokens) = mac::parse_delimiter(input)?;
+        Ok(MetaList {
+            path,
+            delimiter,
+            tokens,
+        })
+    }
+
+    fn parse_meta_name_value_after_path(path: Path, input: ParseStream) -> Result<MetaNameValue> {
+        let eq_token: Token![=] = input.parse()?;
+        let ahead = input.fork();
+        let lit: Option<Lit> = ahead.parse()?;
+        let value = if let (Some(lit), true) = (lit, ahead.is_empty()) {
+            input.advance_to(&ahead);
+            Expr::Lit(ExprLit {
+                attrs: Vec::new(),
+                lit,
+            })
+        } else if input.peek(Token![#]) && input.peek2(token::Bracket) {
+            return Err(input.error("unexpected attribute inside of attribute"));
+        } else {
+            input.parse()?
+        };
+        Ok(MetaNameValue {
+            path,
+            eq_token,
+            value,
+        })
+    }
+
+    pub(super) struct DisplayAttrStyle<'a>(pub &'a AttrStyle);
+
+    impl<'a> Display for DisplayAttrStyle<'a> {
+        fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+            formatter.write_str(match self.0 {
+                AttrStyle::Outer => "#",
+                AttrStyle::Inner(_) => "#!",
+            })
+        }
+    }
+
+    pub(super) struct DisplayPath<'a>(pub &'a Path);
+
+    impl<'a> Display for DisplayPath<'a> {
+        fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+            for (i, segment) in self.0.segments.iter().enumerate() {
+                if i > 0 || self.0.leading_colon.is_some() {
+                    formatter.write_str("::")?;
+                }
+                write!(formatter, "{}", segment.ident)?;
+            }
+            Ok(())
+        }
+    }
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+    use crate::attr::{AttrStyle, Attribute, Meta, MetaList, MetaNameValue};
+    use crate::path;
+    use crate::path::printing::PathStyle;
+    use proc_macro2::TokenStream;
+    use quote::ToTokens;
+
+    #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
+    impl ToTokens for Attribute {
+        fn to_tokens(&self, tokens: &mut TokenStream) {
+            self.pound_token.to_tokens(tokens);
+            if let AttrStyle::Inner(b) = &self.style {
+                b.to_tokens(tokens);
+            }
+            self.bracket_token.surround(tokens, |tokens| {
+                self.meta.to_tokens(tokens);
+            });
+        }
+    }
+
+    #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
+    impl ToTokens for Meta {
+        fn to_tokens(&self, tokens: &mut TokenStream) {
+            match self {
+                Meta::Path(path) => path::printing::print_path(tokens, path, PathStyle::Mod),
+                Meta::List(meta_list) => meta_list.to_tokens(tokens),
+                Meta::NameValue(meta_name_value) => meta_name_value.to_tokens(tokens),
+            }
+        }
+    }
+
+    #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
+    impl ToTokens for MetaList {
+        fn to_tokens(&self, tokens: &mut TokenStream) {
+            path::printing::print_path(tokens, &self.path, PathStyle::Mod);
+            self.delimiter.surround(tokens, self.tokens.clone());
+        }
+    }
+
+    #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
+    impl ToTokens for MetaNameValue {
+        fn to_tokens(&self, tokens: &mut TokenStream) {
+            path::printing::print_path(tokens, &self.path, PathStyle::Mod);
+            self.eq_token.to_tokens(tokens);
+            self.value.to_tokens(tokens);
+        }
+    }
+}
rust/syn/bigint.rs new file +66 -0

66 lines not on this page · raw message

rust/syn/buffer.rs new file +434 -0

434 lines not on this page · raw message

rust/syn/classify.rs new file +311 -0

311 lines not on this page · raw message

rust/syn/custom_keyword.rs new file +260 -0

260 lines not on this page · raw message

rust/syn/custom_punctuation.rs new file +304 -0

304 lines not on this page · raw message

rust/syn/data.rs new file +424 -0

424 lines not on this page · raw message

rust/syn/derive.rs new file +259 -0

259 lines not on this page · raw message

rust/syn/discouraged.rs new file +225 -0

106 lines not on this page · raw message

rust/syn/drops.rs new file +58 -0

58 lines not on this page · raw message

rust/syn/error.rs new file +467 -0

467 lines not on this page · raw message

rust/syn/export.rs new file +73 -0

73 lines not on this page · raw message

rust/syn/expr.rs new file +4173 -0

4,173 lines not on this page · raw message

rust/syn/ext.rs new file +136 -0

136 lines not on this page · raw message

rust/syn/file.rs new file +125 -0

125 lines not on this page · raw message

rust/syn/fixup.rs new file +773 -0

773 lines not on this page · raw message

rust/syn/gen/clone.rs new file +2267 -0

2,267 lines not on this page · raw message

rust/syn/gen/debug.rs new file +3238 -0

3,238 lines not on this page · raw message

rust/syn/gen/eq.rs new file +2306 -0

2,306 lines not on this page · raw message

rust/syn/gen/fold.rs new file +3902 -0

3,902 lines not on this page · raw message

rust/syn/gen/hash.rs new file +2876 -0

2,876 lines not on this page · raw message

rust/syn/gen/visit.rs new file +3941 -0

3,941 lines not on this page · raw message

rust/syn/gen/visit_mut.rs new file +3759 -0

3,759 lines not on this page · raw message

rust/syn/generics.rs new file +1477 -0

1,477 lines not on this page · raw message

rust/syn/group.rs new file +291 -0

291 lines not on this page · raw message

rust/syn/ident.rs new file +108 -0

108 lines not on this page · raw message

rust/syn/item.rs new file +3490 -0

3,490 lines not on this page · raw message

rust/syn/lib.rs new file +1011 -0

1,011 lines not on this page · raw message

rust/syn/lifetime.rs new file +156 -0

156 lines not on this page · raw message

rust/syn/lit.rs new file +1860 -0

1,860 lines not on this page · raw message

rust/syn/lookahead.rs new file +332 -0

332 lines not on this page · raw message

rust/syn/mac.rs new file +225 -0

225 lines not on this page · raw message

rust/syn/macros.rs new file +182 -0

182 lines not on this page · raw message

rust/syn/meta.rs new file +427 -0

427 lines not on this page · raw message

rust/syn/op.rs new file +219 -0

219 lines not on this page · raw message

rust/syn/parse.rs new file +1419 -0

1,419 lines not on this page · raw message

rust/syn/parse_macro_input.rs new file +128 -0

128 lines not on this page · raw message

rust/syn/parse_quote.rs new file +240 -0

240 lines not on this page · raw message

rust/syn/pat.rs new file +955 -0

955 lines not on this page · raw message

rust/syn/path.rs new file +966 -0

966 lines not on this page · raw message

rust/syn/precedence.rs new file +210 -0

210 lines not on this page · raw message

rust/syn/print.rs new file +16 -0
new file mode 100644
index 000000000000..07409932677b

Lines of this file are not shown. View the raw message.

rust/syn/punctuated.rs new file +1155 -0

1,155 lines not on this page · raw message

rust/syn/restriction.rs new file +178 -0

178 lines not on this page · raw message

rust/syn/scan_expr.rs new file +265 -0

265 lines not on this page · raw message

rust/syn/sealed.rs new file +4 -0
new file mode 100644
index 000000000000..dc804742d12d

Lines of this file are not shown. View the raw message.

rust/syn/span.rs new file +63 -0

63 lines not on this page · raw message

rust/syn/spanned.rs new file +118 -0

118 lines not on this page · raw message

rust/syn/stmt.rs new file +484 -0

484 lines not on this page · raw message

rust/syn/thread.rs new file +60 -0

60 lines not on this page · raw message

rust/syn/token.rs new file +1096 -0

1,096 lines not on this page · raw message

rust/syn/tt.rs new file +107 -0

107 lines not on this page · raw message

rust/syn/ty.rs new file +1271 -0

1,271 lines not on this page · raw message

rust/syn/verbatim.rs new file +33 -0
new file mode 100644
index 000000000000..54dc1cfa0d82

Lines of this file are not shown. View the raw message.

rust/syn/whitespace.rs new file +65 -0

65 lines not on this page · raw message

The rest of this diff is not shown. View the raw message.

Signature · 1 line
2.52.0

Part of the diff is not shown here. View the raw message.

author maintainer
#16 lore raw

PATCH v2 16/20 rust: syn: add SPDX License Identifiers

In reply to Miguel Ojeda

Originally, when the Rust upstream alloc standard library crate was vendored in commit 057b8d257107 ("rust: adapt alloc crate to the kernel"), the SPDX License Identifiers were added to every file so that the license on those was clear.

Thus do the same for the syn crate.

This makes scripts/spdxcheck.py pass.

---
 rust/syn/attr.rs               | 2 ++
 rust/syn/bigint.rs             | 2 ++
 rust/syn/buffer.rs             | 2 ++
 rust/syn/classify.rs           | 2 ++
 rust/syn/custom_keyword.rs     | 2 ++
 rust/syn/custom_punctuation.rs | 2 ++
 rust/syn/data.rs               | 2 ++
 rust/syn/derive.rs             | 2 ++
 rust/syn/discouraged.rs        | 2 ++
 rust/syn/drops.rs              | 2 ++
 rust/syn/error.rs              | 2 ++
 rust/syn/export.rs             | 2 ++
 rust/syn/expr.rs               | 2 ++
 rust/syn/ext.rs                | 2 ++
 rust/syn/file.rs               | 2 ++
 rust/syn/fixup.rs              | 2 ++
 rust/syn/gen/clone.rs          | 2 ++
 rust/syn/gen/debug.rs          | 2 ++
 rust/syn/gen/eq.rs             | 2 ++
 rust/syn/gen/fold.rs           | 2 ++
 rust/syn/gen/hash.rs           | 2 ++
 rust/syn/gen/visit.rs          | 2 ++
 rust/syn/gen/visit_mut.rs      | 2 ++
 rust/syn/generics.rs           | 2 ++
 rust/syn/group.rs              | 2 ++
 rust/syn/ident.rs              | 2 ++
 rust/syn/item.rs               | 2 ++
 rust/syn/lib.rs                | 2 ++
 rust/syn/lifetime.rs           | 2 ++
 rust/syn/lit.rs                | 2 ++
 rust/syn/lookahead.rs          | 2 ++
 rust/syn/mac.rs                | 2 ++
 rust/syn/macros.rs             | 2 ++
 rust/syn/meta.rs               | 2 ++
 rust/syn/op.rs                 | 2 ++
 rust/syn/parse.rs              | 2 ++
 rust/syn/parse_macro_input.rs  | 2 ++
 rust/syn/parse_quote.rs        | 2 ++
 rust/syn/pat.rs                | 2 ++
 rust/syn/path.rs               | 2 ++
 rust/syn/precedence.rs         | 2 ++
 rust/syn/print.rs              | 2 ++
 rust/syn/punctuated.rs         | 2 ++
 rust/syn/restriction.rs        | 2 ++
 rust/syn/scan_expr.rs          | 2 ++
 rust/syn/sealed.rs             | 2 ++
 rust/syn/span.rs               | 2 ++
 rust/syn/spanned.rs            | 2 ++
 rust/syn/stmt.rs               | 2 ++
 rust/syn/thread.rs             | 2 ++
 rust/syn/token.rs              | 2 ++
 rust/syn/tt.rs                 | 2 ++
 rust/syn/ty.rs                 | 2 ++
 rust/syn/verbatim.rs           | 2 ++
 rust/syn/whitespace.rs         | 2 ++
 55 files changed, 110 insertions(+)
rust/syn/attr.rs +2 -0
index 2bdf96ee7fa9..020b31f9de22 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 #[cfg(feature = "parsing")]
 use crate::error::Error;
 #[cfg(feature = "parsing")]
rust/syn/bigint.rs +2 -0
index 66aaa9372540..d706f9f515e9 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 use std::ops::{AddAssign, MulAssign};
 
 // For implementing base10_digits() accessor on LitInt.
rust/syn/buffer.rs +2 -0
index 7b6a504eeb7c..406f70db323c 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 //! A stably addressed token buffer supporting efficient traversal based on a
 //! cheaply copyable cursor.
 
rust/syn/classify.rs +2 -0
index 8eab19dbc37c..92a975bfe4aa 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 #[cfg(feature = "full")]
 use crate::expr::Expr;
 #[cfg(any(feature = "printing", feature = "full"))]
rust/syn/custom_keyword.rs +2 -0
index cc4f632c981a..ff2c415f1aab 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 /// Define a type that supports parsing and printing a given identifier as if it
 /// were a keyword.
 ///
rust/syn/custom_punctuation.rs +2 -0
index eef5f5458459..d37c0e9c3a1e 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 /// Define a type that supports parsing and printing a multi-character symbol
 /// as if it were a punctuation token.
 ///
rust/syn/data.rs +2 -0
index 96db2a0b7c6f..c32c1366c1db 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 use crate::attr::Attribute;
 use crate::expr::{Expr, Index, Member};
 use crate::ident::Ident;
rust/syn/derive.rs +2 -0
index 3443ecfc05cb..27fd9f12c88c 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 use crate::attr::Attribute;
 use crate::data::{Fields, FieldsNamed, Variant};
 use crate::generics::Generics;
rust/syn/discouraged.rs +2 -0
index c8d6bfe89a14..2acd631ece84 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 //! Extensions to the parsing API with niche applicability.
 
 use crate::buffer::Cursor;
rust/syn/drops.rs +2 -0
index c54308f02c13..2c4ae333dad8 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 use std::iter;
 use std::mem::ManuallyDrop;
 use std::ops::{Deref, DerefMut};
rust/syn/error.rs +2 -0
index 63310543a3b4..6fa0faf7f4e4 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 #[cfg(feature = "parsing")]
 use crate::buffer::Cursor;
 use crate::thread::ThreadBound;
rust/syn/export.rs +2 -0
index b9ea5c747b75..05dad324ba51 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 #[doc(hidden)]
 pub use std::clone::Clone;
 #[doc(hidden)]
rust/syn/expr.rs +2 -0
index 1e49d9a6633e..deb918436604 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 use crate::attr::Attribute;
 #[cfg(all(feature = "parsing", feature = "full"))]
 use crate::error::Result;
rust/syn/ext.rs +2 -0
index 5cd79e863a9d..a9be9af42787 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 //! Extension traits to provide parsing methods on foreign types.
 
 use crate::buffer::Cursor;
rust/syn/file.rs +2 -0
index 8956d82eee93..ce2d2680ca9a 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 use crate::attr::Attribute;
 use crate::item::Item;
 
rust/syn/fixup.rs +2 -0
index 6d2c3092d548..79b6d7618bb7 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 use crate::classify;
 use crate::expr::Expr;
 #[cfg(feature = "full")]
rust/syn/gen/clone.rs +2 -0
index be2b698422da..dfb53182e378 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 // This file is @generated by syn-internal-codegen.
 // It is not intended for manual editing.
 
rust/syn/gen/debug.rs +2 -0
index aa42e32c60ed..d594e57fcf21 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 // This file is @generated by syn-internal-codegen.
 // It is not intended for manual editing.
 
rust/syn/gen/eq.rs +2 -0
index 128e8991eecc..79e9691b8c67 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 // This file is @generated by syn-internal-codegen.
 // It is not intended for manual editing.
 
rust/syn/gen/fold.rs +2 -0
index 1f0afd31919d..0643a72f87ca 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 // This file is @generated by syn-internal-codegen.
 // It is not intended for manual editing.
 
rust/syn/gen/hash.rs +2 -0
index 04f23453a117..fae2197a5610 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 // This file is @generated by syn-internal-codegen.
 // It is not intended for manual editing.
 
rust/syn/gen/visit.rs +2 -0
index cd258fcde120..a82293c053d6 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 // This file is @generated by syn-internal-codegen.
 // It is not intended for manual editing.
 
rust/syn/gen/visit_mut.rs +2 -0
index 2bbd6895db75..08e134b43a92 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 // This file is @generated by syn-internal-codegen.
 // It is not intended for manual editing.
 
rust/syn/generics.rs +2 -0
index 0c77193da043..9f8df8a155e1 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 use crate::attr::Attribute;
 use crate::expr::Expr;
 use crate::ident::Ident;
rust/syn/group.rs +2 -0
index 1534ae995dd5..57586c58fd92 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 use crate::error::Result;
 use crate::parse::ParseBuffer;
 use crate::token;
rust/syn/ident.rs +2 -0
index 8a8e8a50d9b0..2c4b56505bec 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 #[cfg(feature = "parsing")]
 use crate::lookahead;
 
rust/syn/item.rs +2 -0
index 1716f5137afb..1ab10cf218a6 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 use crate::attr::Attribute;
 use crate::data::{Fields, FieldsNamed, Variant};
 use crate::derive::{Data, DataEnum, DataStruct, DataUnion, DeriveInput};
rust/syn/lib.rs +2 -0
index 79dc9e7c3324..b0006fd30b08 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 //! [![github]](https://github.com/dtolnay/syn)&ensp;[![crates-io]](https://crates.io/crates/syn)&ensp;[![docs-rs]](crate)
 //!
 //! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
rust/syn/lifetime.rs +2 -0
index cc189d1ac91f..24bec7fe969d 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 #[cfg(feature = "parsing")]
 use crate::lookahead;
 use proc_macro2::{Ident, Span};
rust/syn/lit.rs +2 -0
index 45c26d56fed3..1d2d8bdccfb1 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 #[cfg(feature = "parsing")]
 use crate::lookahead;
 #[cfg(feature = "parsing")]
rust/syn/lookahead.rs +2 -0
index da13ffc47a7a..a7994cb6ae88 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 use crate::buffer::Cursor;
 use crate::error::{self, Error};
 use crate::sealed::lookahead::Sealed;
rust/syn/mac.rs +2 -0
index 15107801cfee..ce4b022b4d14 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 #[cfg(feature = "parsing")]
 use crate::error::Result;
 #[cfg(feature = "parsing")]
rust/syn/macros.rs +2 -0
index 167f2cf260a7..8676f6492a9c 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 #[cfg_attr(
     not(any(feature = "full", feature = "derive")),
     allow(unknown_lints, unused_macro_rules)
rust/syn/meta.rs +2 -0
index ffeeb2629f4f..2dd138e6dd55 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 //! Facility for interpreting structured content inside of an `Attribute`.
 
 use crate::error::{Error, Result};
rust/syn/op.rs +2 -0
index 575d9faa1273..73dada3fae2d 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 ast_enum! {
     /// A binary operator: `+`, `+=`, `&`.
     #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
rust/syn/parse.rs +2 -0
index 57531005ac4e..c6f6c0eece02 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 //! Parsing interface for parsing a token stream into a syntax tree node.
 //!
 //! Parsing in Syn is built on parser functions that take in a [`ParseStream`]
rust/syn/parse_macro_input.rs +2 -0
index f0660aedd7df..2f977754d41c 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 /// Parse the input TokenStream of a macro, triggering a compile error if the
 /// tokens fail to parse.
 ///
rust/syn/parse_quote.rs +2 -0
index 2db20597c436..7cc7b9b8fd75 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 /// Quasi-quotation macro that accepts input like the [`quote!`] macro but uses
 /// type inference to figure out a return type for those tokens.
 ///
rust/syn/pat.rs +2 -0
index 81a2f183f6b9..46edd63d5ed8 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 use crate::attr::Attribute;
 use crate::expr::Member;
 use crate::ident::Ident;
rust/syn/path.rs +2 -0
index d2fcb9bc5d28..f2453bea4a3c 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 #[cfg(feature = "parsing")]
 use crate::error::Result;
 use crate::expr::Expr;
rust/syn/precedence.rs +2 -0
index 1891bfc202fd..cc4dba24a433 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 #[cfg(all(feature = "printing", feature = "full"))]
 use crate::attr::{AttrStyle, Attribute};
 #[cfg(feature = "printing")]
rust/syn/print.rs +2 -0
index 07409932677b..d73262cda060 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 use proc_macro2::TokenStream;
 use quote::ToTokens;
 
rust/syn/punctuated.rs +2 -0
index ebaaa94f9a26..f79152940db6 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 //! A punctuated sequence of syntax tree nodes separated by punctuation.
 //!
 //! Lots of things in Rust are punctuated sequences.
rust/syn/restriction.rs +2 -0
index 6e6758f3cd73..b844f64c3a73 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 use crate::path::Path;
 use crate::token;
 
rust/syn/scan_expr.rs +2 -0
index 3d88cf06acea..a5fd1ddc1501 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 use self::{Action::*, Input::*};
 use proc_macro2::{Delimiter, Ident, Spacing, TokenTree};
 use syn::parse::{ParseStream, Result};
rust/syn/sealed.rs +2 -0
index dc804742d12d..541df9623755 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 #[cfg(feature = "parsing")]
 pub(crate) mod lookahead {
     pub trait Sealed: Copy {}
rust/syn/span.rs +2 -0
index eb2779479aaa..e6d55b3ccd03 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 use proc_macro2::extra::DelimSpan;
 use proc_macro2::{Delimiter, Group, Span, TokenStream};
 
rust/syn/spanned.rs +2 -0
index 17b69e9f5b28..fcc93699f742 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 //! A trait that can provide the `Span` of the complete contents of a syntax
 //! tree node.
 //!
rust/syn/stmt.rs +2 -0
index 8ea0077f63df..029171a98dca 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 use crate::attr::Attribute;
 use crate::expr::Expr;
 use crate::item::Item;
rust/syn/thread.rs +2 -0
index b33d248afc60..4165a173d9e1 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 use std::fmt::{self, Debug};
 use std::thread::{self, ThreadId};
 
rust/syn/token.rs +2 -0
index 752c188883cb..18345cc5831a 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 //! Tokens representing Rust punctuation, keywords, and delimiters.
 //!
 //! The type names in this module can be difficult to keep straight, so we
rust/syn/tt.rs +2 -0
index 7d5d6a1ac326..fc7adec3da90 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 use proc_macro2::{Delimiter, TokenStream, TokenTree};
 use std::hash::{Hash, Hasher};
 
rust/syn/ty.rs +2 -0
index c093f5877b3c..ae660d2d2e74 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 use crate::attr::Attribute;
 use crate::expr::Expr;
 use crate::generics::{BoundLifetimes, TypeParamBound};
rust/syn/verbatim.rs +2 -0
index 54dc1cfa0d82..97bc08f70afe 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 use crate::parse::ParseStream;
 use proc_macro2::{Delimiter, TokenStream};
 use std::cmp::Ordering;
rust/syn/whitespace.rs +2 -0
index a50b5069a68b..b7319bd7af18 100644
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
 pub(crate) fn skip(mut s: &str) -> &str {
     'skip: while !s.is_empty() {
         let byte = s.as_bytes()[0];
Signature · 1 line
2.52.0
author maintainer
#17 lore raw

PATCH v2 17/20 rust: syn: remove `unicode-ident` dependency

In reply to Miguel Ojeda

The syn crate depends on the unicode-ident crate to determine whether characters have the XID_Start or XID_Continue properties according to Unicode Standard Annex #31.

However, we only need ASCII identifiers in the kernel, thus we can simplify the check and remove completely that dependency.

---
 rust/syn/ident.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
rust/syn/ident.rs +2 -2
index 2c4b56505bec..03ccebf9c022 100644
@@ -39,11 +39,11 @@ fn from(token: Token![_]) -> Ident {
 pub(crate) fn xid_ok(symbol: &str) -> bool {
     let mut chars = symbol.chars();
     let first = chars.next().unwrap();
-    if !(first == '_' || unicode_ident::is_xid_start(first)) {
+    if !(first == '_' || first.is_ascii_alphabetic()) {
         return false;
     }
     for ch in chars {
-        if !unicode_ident::is_xid_continue(ch) {
+        if !(ch == '_' || ch.is_ascii_alphanumeric()) {
             return false;
         }
     }
Signature · 1 line
2.52.0
author maintainer
#18 lore raw

PATCH v2 18/20 rust: syn: add `README.md`

In reply to Miguel Ojeda

Originally, when the Rust upstream alloc standard library crate was vendored in commit 057b8d257107 ("rust: adapt alloc crate to the kernel"), a README.md file was added to explain the provenance and licensing of the source files.

Thus do the same for the syn crate.

---
 rust/syn/README.md | 13 +++++++++++++
 1 file changed, 13 insertions(+)
 create mode 100644 rust/syn/README.md
rust/syn/README.md new file +13 -0
new file mode 100644
index 000000000000..d3e3981da2fe
@@ -0,0 +1,13 @@
+# `syn`
+
+These source files come from the Rust `syn` crate, version 2.0.106
+(released 2025-08-16), hosted in the <https://github.com/dtolnay/syn>
+repository, licensed under "Apache-2.0 OR MIT" and only modified to add
+the SPDX license identifiers and to remove the `unicode-ident`
+dependency.
+
+For copyright details, please see:
+
+    https://github.com/dtolnay/syn/blob/2.0.106/README.md#license
+    https://github.com/dtolnay/syn/blob/2.0.106/LICENSE-APACHE
+    https://github.com/dtolnay/syn/blob/2.0.106/LICENSE-MIT
Signature · 1 line
2.52.0
author maintainer
#19 lore raw

PATCH v2 19/20 rust: syn: enable support in kbuild

In reply to Miguel Ojeda

With all the new files in place and ready from the new crate, enable the support for it in the build system.

---
 Makefile                          |  1 +
 rust/Makefile                     | 37 ++++++++++++++++++++++++++++---
 scripts/generate_rust_analyzer.py |  7 ++++++
 3 files changed, 42 insertions(+), 3 deletions(-)
Makefile +1 -0
index 85da055e4f00..96ddbaae7e12 100644
@@ -1835,6 +1835,7 @@ rustfmt:
 		\( \
 			-path $(srctree)/rust/proc-macro2 \
 			-o -path $(srctree)/rust/quote \
+			-o -path $(srctree)/rust/syn \
 		\) -prune -o \
 		-type f -a -name '*.rs' -a ! -name '*generated*' -print \
 		| xargs $(RUSTFMT) $(rustfmt_flags)
rust/Makefile +34 -3
index 4f4a00594142..8988ecf32531 100644
@@ -27,7 +27,7 @@ endif
 
 obj-$(CONFIG_RUST) += exports.o
 
-always-$(CONFIG_RUST) += libproc_macro2.rlib libquote.rlib
+always-$(CONFIG_RUST) += libproc_macro2.rlib libquote.rlib libsyn.rlib
 
 always-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated.rs
 always-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated_kunit.c
@@ -101,6 +101,22 @@ quote-flags := \
     --extern proc_macro2 \
     $(call cfgs-to-flags,$(quote-cfgs))
 
+# `extra-traits`, `fold` and `visit` may be enabled if needed.
+syn-cfgs := \
+    feature="clone-impls" \
+    feature="derive" \
+    feature="full" \
+    feature="parsing" \
+    feature="printing" \
+    feature="proc-macro" \
+    feature="visit-mut"
+
+syn-flags := \
+    --cap-lints=allow \
+    --extern proc_macro2 \
+    --extern quote \
+    $(call cfgs-to-flags,$(syn-cfgs))
+
 # `rustdoc` did not save the target modifiers, thus workaround for
 # the time being (https://github.com/rust-lang/rust/issues/144521).
 rustdoc_modifiers_workaround := $(if $(call rustc-min-version,108800),-Cunsafe-allow-abi-mismatch=fixed-x18)
@@ -161,11 +177,16 @@ rustdoc-quote: private skip_flags = $(quote-skip_flags)
 rustdoc-quote: $(src)/quote/lib.rs rustdoc-clean rustdoc-proc_macro2 FORCE
 	+$(call if_changed,rustdoc)
 
+rustdoc-syn: private rustdoc_host = yes
+rustdoc-syn: private rustc_target_flags = $(syn-flags)
+rustdoc-syn: $(src)/syn/lib.rs rustdoc-clean rustdoc-quote FORCE
+	+$(call if_changed,rustdoc)
+
 rustdoc-macros: private rustdoc_host = yes
 rustdoc-macros: private rustc_target_flags = --crate-type proc-macro \
     --extern proc_macro
 rustdoc-macros: $(src)/macros/lib.rs rustdoc-clean rustdoc-proc_macro2 \
-    rustdoc-quote FORCE
+    rustdoc-quote rustdoc-syn FORCE
 	+$(call if_changed,rustdoc)
 
 # Starting with Rust 1.82.0, skipping `-Wrustdoc::unescaped_backticks` should
@@ -231,6 +252,10 @@ rusttestlib-quote: private rustc_target_flags = $(quote-flags)
 rusttestlib-quote: $(src)/quote/lib.rs rusttestlib-proc_macro2 FORCE
 	+$(call if_changed,rustc_test_library)
 
+rusttestlib-syn: private rustc_target_flags = $(syn-flags)
+rusttestlib-syn: $(src)/syn/lib.rs rusttestlib-quote FORCE
+	+$(call if_changed,rustc_test_library)
+
 rusttestlib-macros: private rustc_target_flags = --extern proc_macro
 rusttestlib-macros: private rustc_test_library_proc = yes
 rusttestlib-macros: $(src)/macros/lib.rs FORCE
@@ -488,6 +513,11 @@ $(obj)/libquote.rlib: private rustc_target_flags = $(quote-flags)
 $(obj)/libquote.rlib: $(src)/quote/lib.rs $(obj)/libproc_macro2.rlib FORCE
 	+$(call if_changed_dep,rustc_procmacrolibrary)
 
+$(obj)/libsyn.rlib: private skip_clippy = 1
+$(obj)/libsyn.rlib: private rustc_target_flags = $(syn-flags)
+$(obj)/libsyn.rlib: $(src)/syn/lib.rs $(obj)/libquote.rlib FORCE
+	+$(call if_changed_dep,rustc_procmacrolibrary)
+
 quiet_cmd_rustc_procmacro = $(RUSTC_OR_CLIPPY_QUIET) P $@
       cmd_rustc_procmacro = \
 	$(RUSTC_OR_CLIPPY) $(rust_common_flags) $(rustc_target_flags) \
@@ -500,7 +530,7 @@ quiet_cmd_rustc_procmacro = $(RUSTC_OR_CLIPPY_QUIET) P $@
 
 # Procedural macros can only be used with the `rustc` that compiled it.
 $(obj)/$(libmacros_name): $(src)/macros/lib.rs $(obj)/libproc_macro2.rlib \
-    $(obj)/libquote.rlib FORCE
+    $(obj)/libquote.rlib $(obj)/libsyn.rlib FORCE
 	+$(call if_changed_dep,rustc_procmacro)
 
 $(obj)/$(libpin_init_internal_name): private rustc_target_flags = --cfg kernel
@@ -525,6 +555,7 @@ rust-analyzer:
 		--cfgs='core=$(core-cfgs)' $(core-edition) \
 		--cfgs='proc_macro2=$(proc_macro2-cfgs)' \
 		--cfgs='quote=$(quote-cfgs)' \
+		--cfgs='syn=$(syn-cfgs)' \
 		$(realpath $(srctree)) $(realpath $(objtree)) \
 		$(rustc_sysroot) $(RUST_LIB_SRC) $(if $(KBUILD_EXTMOD),$(srcroot)) \
 		> rust-project.json
scripts/generate_rust_analyzer.py +7 -0
index 4faf153ed2ee..5b6f7b8d6918 100755
@@ -100,6 +100,13 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edit
         cfg=crates_cfgs["quote"],
     )
 
+    append_crate(
+        "syn",
+        srctree / "rust" / "syn" / "lib.rs",
+        ["proc_macro", "proc_macro2", "quote"],
+        cfg=crates_cfgs["syn"],
+    )
+
     append_crate(
         "macros",
         srctree / "rust" / "macros" / "lib.rs",
Signature · 1 line
2.52.0
#20 lore raw

Re: [PATCH v2 19/20] rust: syn: enable support in kbuild

Quoted 126 lines · Miguel Ojeda

With all the new files in place and ready from the new crate, enable the support for it in the build system.

---
 Makefile                          |  1 +
 rust/Makefile                     | 37 ++++++++++++++++++++++++++++---
 scripts/generate_rust_analyzer.py |  7 ++++++
 3 files changed, 42 insertions(+), 3 deletions(-)
Makefile +1 -0
index 85da055e4f00..96ddbaae7e12 100644
@@ -1835,6 +1835,7 @@ rustfmt:
                \( \
                        -path $(srctree)/rust/proc-macro2 \
                        -o -path $(srctree)/rust/quote \
+                       -o -path $(srctree)/rust/syn \
                \) -prune -o \
                -type f -a -name '*.rs' -a ! -name '*generated*' -print \
                | xargs $(RUSTFMT) $(rustfmt_flags)
rust/Makefile +34 -3
index 4f4a00594142..8988ecf32531 100644
@@ -27,7 +27,7 @@ endif
 
 obj-$(CONFIG_RUST) += exports.o
 
-always-$(CONFIG_RUST) += libproc_macro2.rlib libquote.rlib
+always-$(CONFIG_RUST) += libproc_macro2.rlib libquote.rlib libsyn.rlib
 
 always-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated.rs
 always-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated_kunit.c
@@ -101,6 +101,22 @@ quote-flags := \
     --extern proc_macro2 \
     $(call cfgs-to-flags,$(quote-cfgs))
 
+# `extra-traits`, `fold` and `visit` may be enabled if needed.
+syn-cfgs := \
+    feature="clone-impls" \
+    feature="derive" \
+    feature="full" \
+    feature="parsing" \
+    feature="printing" \
+    feature="proc-macro" \
+    feature="visit-mut"
+
+syn-flags := \
+    --cap-lints=allow \
+    --extern proc_macro2 \
+    --extern quote \
+    $(call cfgs-to-flags,$(syn-cfgs))
+
 # `rustdoc` did not save the target modifiers, thus workaround for
 # the time being (https://github.com/rust-lang/rust/issues/144521).
 rustdoc_modifiers_workaround := $(if $(call rustc-min-version,108800),-Cunsafe-allow-abi-mismatch=fixed-x18)
@@ -161,11 +177,16 @@ rustdoc-quote: private skip_flags = $(quote-skip_flags)
 rustdoc-quote: $(src)/quote/lib.rs rustdoc-clean rustdoc-proc_macro2 FORCE
        +$(call if_changed,rustdoc)
 
+rustdoc-syn: private rustdoc_host = yes
+rustdoc-syn: private rustc_target_flags = $(syn-flags)
+rustdoc-syn: $(src)/syn/lib.rs rustdoc-clean rustdoc-quote FORCE
+       +$(call if_changed,rustdoc)
+
 rustdoc-macros: private rustdoc_host = yes
 rustdoc-macros: private rustc_target_flags = --crate-type proc-macro \
     --extern proc_macro
 rustdoc-macros: $(src)/macros/lib.rs rustdoc-clean rustdoc-proc_macro2 \
-    rustdoc-quote FORCE
+    rustdoc-quote rustdoc-syn FORCE
        +$(call if_changed,rustdoc)
 
 # Starting with Rust 1.82.0, skipping `-Wrustdoc::unescaped_backticks` should
@@ -231,6 +252,10 @@ rusttestlib-quote: private rustc_target_flags = $(quote-flags)
 rusttestlib-quote: $(src)/quote/lib.rs rusttestlib-proc_macro2 FORCE
        +$(call if_changed,rustc_test_library)
 
+rusttestlib-syn: private rustc_target_flags = $(syn-flags)
+rusttestlib-syn: $(src)/syn/lib.rs rusttestlib-quote FORCE
+       +$(call if_changed,rustc_test_library)
+
 rusttestlib-macros: private rustc_target_flags = --extern proc_macro
 rusttestlib-macros: private rustc_test_library_proc = yes
 rusttestlib-macros: $(src)/macros/lib.rs FORCE
@@ -488,6 +513,11 @@ $(obj)/libquote.rlib: private rustc_target_flags = $(quote-flags)
 $(obj)/libquote.rlib: $(src)/quote/lib.rs $(obj)/libproc_macro2.rlib FORCE
        +$(call if_changed_dep,rustc_procmacrolibrary)
 
+$(obj)/libsyn.rlib: private skip_clippy = 1
+$(obj)/libsyn.rlib: private rustc_target_flags = $(syn-flags)
+$(obj)/libsyn.rlib: $(src)/syn/lib.rs $(obj)/libquote.rlib FORCE
+       +$(call if_changed_dep,rustc_procmacrolibrary)
+
 quiet_cmd_rustc_procmacro = $(RUSTC_OR_CLIPPY_QUIET) P $@
       cmd_rustc_procmacro = \
        $(RUSTC_OR_CLIPPY) $(rust_common_flags) $(rustc_target_flags) \
@@ -500,7 +530,7 @@ quiet_cmd_rustc_procmacro = $(RUSTC_OR_CLIPPY_QUIET) P $@
 
 # Procedural macros can only be used with the `rustc` that compiled it.
 $(obj)/$(libmacros_name): $(src)/macros/lib.rs $(obj)/libproc_macro2.rlib \
-    $(obj)/libquote.rlib FORCE
+    $(obj)/libquote.rlib $(obj)/libsyn.rlib FORCE
        +$(call if_changed_dep,rustc_procmacro)
 
 $(obj)/$(libpin_init_internal_name): private rustc_target_flags = --cfg kernel
@@ -525,6 +555,7 @@ rust-analyzer:
                --cfgs='core=$(core-cfgs)' $(core-edition) \
                --cfgs='proc_macro2=$(proc_macro2-cfgs)' \
                --cfgs='quote=$(quote-cfgs)' \
+               --cfgs='syn=$(syn-cfgs)' \
                $(realpath $(srctree)) $(realpath $(objtree)) \
                $(rustc_sysroot) $(RUST_LIB_SRC) $(if $(KBUILD_EXTMOD),$(srcroot)) \
                > rust-project.json
scripts/generate_rust_analyzer.py +0 -0
index 4faf153ed2ee..5b6f7b8d6918 100755

scripts/generate_rust_analyzer.py def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edit · line 108

Quoted 9 lines
scripts/generate_rust_analyzer.py +6 -0
@@ -100,6 +100,13 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edit
         cfg=crates_cfgs["quote"],
     )
 
+    append_crate(
+        "syn",
+        srctree / "rust" / "syn" / "lib.rs",
+        ["proc_macro", "proc_macro2", "quote"],
+        cfg=crates_cfgs["syn"],
+    )

I think we need to add "std" here -- without it, navigating to methods on e.g. Vec items defined in syn doesn't work (it does work with "std" added).

Quoted 8 lines
scripts/generate_rust_analyzer.py +1 -1
+
     append_crate(
         "macros",
         srctree / "rust" / "macros" / "lib.rs",
--

2.52.0

reviewer
#21 lore raw

Re: [PATCH v2 19/20] rust: syn: enable support in kbuild

Quoted 1 line · Tamir Duberstein

On Mon, Nov 24, 2025 at 10:25 AM Miguel Ojeda <[email protected]> wrote:

[...]

Quoted 8 lines
Quoted 8 lines
scripts/generate_rust_analyzer.py +0 -0
index 4faf153ed2ee..5b6f7b8d6918 100755
@@ -100,6 +100,13 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edit
         cfg=crates_cfgs["quote"],
     )
 
Quoted 10 lines

scripts/generate_rust_analyzer.py def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edit · line 108

Quoted 6 lines
scripts/generate_rust_analyzer.py +6 -0
+    append_crate(
+        "syn",
+        srctree / "rust" / "syn" / "lib.rs",
+        ["proc_macro", "proc_macro2", "quote"],
+        cfg=crates_cfgs["syn"],
+    )

I think we need to add "std" here -- without it, navigating to methods on e.g. Vec items defined in syn doesn't work (it does work with "std" added).

This was handled in [1], but hasn't landed yet, probably due to lack of Reviewed-by or Tested-by tags. If anyone has a moment to take a look and provide some tags, it would be appreciated!

[1] https://lore.kernel.org/rust-for-linux/6dbdf6e1c1639ae381ca9ab7041f84728ffa2267.1764062688.git.y.j3ms.n@gmail.com/

Best regards,
Jesung

author maintainer
#22 lore raw

PATCH v2 20/20 rust: macros: support `proc-macro2`, `quote` and `syn`

In reply to Miguel Ojeda

One of the two main uses cases for adding proc-macro2, quote and syn is the macros crates (and the other pin-init).

Thus add the support for the crates in macros already.

---
 rust/Makefile                     | 13 +++++++++----
 scripts/generate_rust_analyzer.py |  2 +-
 2 files changed, 10 insertions(+), 5 deletions(-)
rust/Makefile +9 -4
index 8988ecf32531..d7d19c21b671 100644
@@ -184,7 +184,7 @@ rustdoc-syn: $(src)/syn/lib.rs rustdoc-clean rustdoc-quote FORCE
 
 rustdoc-macros: private rustdoc_host = yes
 rustdoc-macros: private rustc_target_flags = --crate-type proc-macro \
-    --extern proc_macro
+    --extern proc_macro --extern proc_macro2 --extern quote --extern syn
 rustdoc-macros: $(src)/macros/lib.rs rustdoc-clean rustdoc-proc_macro2 \
     rustdoc-quote rustdoc-syn FORCE
 	+$(call if_changed,rustdoc)
@@ -256,9 +256,11 @@ rusttestlib-syn: private rustc_target_flags = $(syn-flags)
 rusttestlib-syn: $(src)/syn/lib.rs rusttestlib-quote FORCE
 	+$(call if_changed,rustc_test_library)
 
-rusttestlib-macros: private rustc_target_flags = --extern proc_macro
+rusttestlib-macros: private rustc_target_flags = --extern proc_macro \
+    --extern proc_macro2 --extern quote --extern syn
 rusttestlib-macros: private rustc_test_library_proc = yes
-rusttestlib-macros: $(src)/macros/lib.rs FORCE
+rusttestlib-macros: $(src)/macros/lib.rs \
+    rusttestlib-proc_macro2 rusttestlib-quote rusttestlib-syn FORCE
 	+$(call if_changed,rustc_test_library)
 
 rusttestlib-pin_init_internal: private rustc_target_flags = --cfg kernel \
@@ -339,7 +341,8 @@ quiet_cmd_rustc_test = $(RUSTC_OR_CLIPPY_QUIET) T  $<
 rusttest: rusttest-macros
 
 rusttest-macros: private rustc_target_flags = --extern proc_macro \
-	--extern macros --extern kernel --extern pin_init
+    --extern macros --extern kernel --extern pin_init \
+    --extern proc_macro2 --extern quote --extern syn
 rusttest-macros: private rustdoc_test_target_flags = --crate-type proc-macro
 rusttest-macros: $(src)/macros/lib.rs \
     rusttestlib-macros rusttestlib-kernel rusttestlib-pin_init FORCE
@@ -529,6 +532,8 @@ quiet_cmd_rustc_procmacro = $(RUSTC_OR_CLIPPY_QUIET) P $@
 		@$(objtree)/include/generated/rustc_cfg $<
 
 # Procedural macros can only be used with the `rustc` that compiled it.
+$(obj)/$(libmacros_name): private rustc_target_flags = \
+    --extern proc_macro2 --extern quote --extern syn
 $(obj)/$(libmacros_name): $(src)/macros/lib.rs $(obj)/libproc_macro2.rlib \
     $(obj)/libquote.rlib $(obj)/libsyn.rlib FORCE
 	+$(call if_changed_dep,rustc_procmacro)
scripts/generate_rust_analyzer.py +1 -1
index 5b6f7b8d6918..147d0cc94068 100755
@@ -110,7 +110,7 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edit
     append_crate(
         "macros",
         srctree / "rust" / "macros" / "lib.rs",
-        ["std", "proc_macro"],
+        ["std", "proc_macro", "proc_macro2", "quote", "syn"],
         is_proc_macro=True,
     )
 
Signature · 1 line
2.52.0
Applied
#23 lore raw
In reply to Miguel Ojeda
Quoted 8 lines · Miguel Ojeda

This patch series introduces support for syn (and its dependencies):

Syn is a parsing library for parsing a stream of Rust tokens into a syntax tree of Rust source code.

Currently this library is geared toward use in Rust procedural macros, but contains some APIs that may be useful more generally.

Applied to rust-next -- thanks everyone!

I mostly sent this to show how it will look like and because I will use the expanded cover letter as a merge commit to keep it around, since it has now even more context, and it is a nice approach for a long series like this.

Cheers,
Miguel