summaryrefslogtreecommitdiffstats
path: root/rust/syn/classify.rs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-08-19 10:09:22 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-08-19 10:09:22 -0700
commitf4cdf7ca9a1fdcca413157df19753f388a5a224e (patch)
tree60a31895b2446cd7fa27514e8c2843534a0de0da /rust/syn/classify.rs
downloadlinux-stable-f4cdf7ca9a1fdcca413157df19753f388a5a224e.tar.gz
linux-stable-f4cdf7ca9a1fdcca413157df19753f388a5a224e.zip
Merge tag 'media/v7.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-mediagrafted
Pull media updates from Mauro Carvalho Chehab: - v4l2-core: added ISP statistics support and per-block validation - v4l2-core: Allow unknown HDR10 white point and luminance - New camera sensors: Sony IMX678 and IMX471m, Himax HM1092 IR sensor - New codec: Milos: VPU v2.0 codec support - isp driver: gained support for Dreamchip RPPX1 ISP framework - vsp1 driver: gained support for RZ/T2H and RZ/N2H - Novalake driver: gained CVS support for new NVL hardware - dvb-core: fix feed leak on failed DMX_ADD_PID - several driver fixes, cleanups and minor improvements * tag 'media/v7.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (308 commits) media: ipu-bridge: check all DMI entries when overriding sensor rotation media: v4l2-async: avoid deleting unlinked ASC entry on link error media: rzg2l-cru: Align bytesperline to hardware DMA stride requirement media: intel/ipu6: fix async notifier cleanup leak on parse error media: staging/ipu7: fix async notifier UAF on probe error path media: amd: isp4: fix self-deadlock in isp4sd_pwron_and_init() error path media: amd: isp4: release partial allocations in isp4if_alloc_fw_gpumem() media: rcar-isp: Fix VSPX reference leaks media: rcar-isp: Release ISPCORE resources media: i2c: imx415: Release runtime PM reference on VBLANK error media: i2c: imx415: Return test pattern write errors media: renesas: vsp1: Declare index variables in for loop statement media: renesas: vsp1: Make reset control optional to support platforms without a reset line media: dt-bindings: media: renesas,vsp1: Document RZ/T2H and RZ/N2H SoCs media: dt-bindings: media: renesas,fcp: Document RZ/T2H and RZ/N2H SoCs media: nxp: imx8-isi: Add additional 32-bit RGB format support media: nxp: imx8-isi: Add 16-bit raw Bayer format support media: nxp: imx8-isi: Implement per-stream reference counting for multiplexed streams media: nxp: imx8-isi: Use BIT_ULL() for 64-bit stream masks media: nxp: imx8-isi: Correct color map between V4L2 and ISI ...
Diffstat (limited to 'rust/syn/classify.rs')
-rw-r--r--rust/syn/classify.rs313
1 files changed, 313 insertions, 0 deletions
diff --git a/rust/syn/classify.rs b/rust/syn/classify.rs
new file mode 100644
index 000000000..92a975bfe
--- /dev/null
+++ b/rust/syn/classify.rs
@@ -0,0 +1,313 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
+#[cfg(feature = "full")]
+use crate::expr::Expr;
+#[cfg(any(feature = "printing", feature = "full"))]
+use crate::generics::TypeParamBound;
+#[cfg(any(feature = "printing", feature = "full"))]
+use crate::path::{Path, PathArguments};
+#[cfg(any(feature = "printing", feature = "full"))]
+use crate::punctuated::Punctuated;
+#[cfg(any(feature = "printing", feature = "full"))]
+use crate::ty::{ReturnType, Type};
+#[cfg(feature = "full")]
+use proc_macro2::{Delimiter, TokenStream, TokenTree};
+#[cfg(any(feature = "printing", feature = "full"))]
+use std::ops::ControlFlow;
+
+#[cfg(feature = "full")]
+pub(crate) fn requires_semi_to_be_stmt(expr: &Expr) -> bool {
+ match expr {
+ Expr::Macro(expr) => !expr.mac.delimiter.is_brace(),
+ _ => requires_comma_to_be_match_arm(expr),
+ }
+}
+
+#[cfg(feature = "full")]
+pub(crate) fn requires_comma_to_be_match_arm(expr: &Expr) -> bool {
+ match expr {
+ Expr::If(_)
+ | Expr::Match(_)
+ | Expr::Block(_) | Expr::Unsafe(_) // both under ExprKind::Block in rustc
+ | Expr::While(_)
+ | Expr::Loop(_)
+ | Expr::ForLoop(_)
+ | Expr::TryBlock(_)
+ | Expr::Const(_) => false,
+
+ Expr::Array(_)
+ | Expr::Assign(_)
+ | Expr::Async(_)
+ | Expr::Await(_)
+ | Expr::Binary(_)
+ | Expr::Break(_)
+ | Expr::Call(_)
+ | Expr::Cast(_)
+ | Expr::Closure(_)
+ | Expr::Continue(_)
+ | Expr::Field(_)
+ | Expr::Group(_)
+ | Expr::Index(_)
+ | Expr::Infer(_)
+ | Expr::Let(_)
+ | Expr::Lit(_)
+ | Expr::Macro(_)
+ | Expr::MethodCall(_)
+ | Expr::Paren(_)
+ | Expr::Path(_)
+ | Expr::Range(_)
+ | Expr::RawAddr(_)
+ | Expr::Reference(_)
+ | Expr::Repeat(_)
+ | Expr::Return(_)
+ | Expr::Struct(_)
+ | Expr::Try(_)
+ | Expr::Tuple(_)
+ | Expr::Unary(_)
+ | Expr::Yield(_)
+ | Expr::Verbatim(_) => true,
+ }
+}
+
+#[cfg(feature = "printing")]
+pub(crate) fn trailing_unparameterized_path(mut ty: &Type) -> bool {
+ loop {
+ match ty {
+ Type::BareFn(t) => match &t.output {
+ ReturnType::Default => return false,
+ ReturnType::Type(_, ret) => ty = ret,
+ },
+ Type::ImplTrait(t) => match last_type_in_bounds(&t.bounds) {
+ ControlFlow::Break(trailing_path) => return trailing_path,
+ ControlFlow::Continue(t) => ty = t,
+ },
+ Type::Path(t) => match last_type_in_path(&t.path) {
+ ControlFlow::Break(trailing_path) => return trailing_path,
+ ControlFlow::Continue(t) => ty = t,
+ },
+ Type::Ptr(t) => ty = &t.elem,
+ Type::Reference(t) => ty = &t.elem,
+ Type::TraitObject(t) => match last_type_in_bounds(&t.bounds) {
+ ControlFlow::Break(trailing_path) => return trailing_path,
+ ControlFlow::Continue(t) => ty = t,
+ },
+
+ Type::Array(_)
+ | Type::Group(_)
+ | Type::Infer(_)
+ | Type::Macro(_)
+ | Type::Never(_)
+ | Type::Paren(_)
+ | Type::Slice(_)
+ | Type::Tuple(_)
+ | Type::Verbatim(_) => return false,
+ }
+ }
+
+ fn last_type_in_path(path: &Path) -> ControlFlow<bool, &Type> {
+ match &path.segments.last().unwrap().arguments {
+ PathArguments::None => ControlFlow::Break(true),
+ PathArguments::AngleBracketed(_) => ControlFlow::Break(false),
+ PathArguments::Parenthesized(arg) => match &arg.output {
+ ReturnType::Default => ControlFlow::Break(false),
+ ReturnType::Type(_, ret) => ControlFlow::Continue(ret),
+ },
+ }
+ }
+
+ fn last_type_in_bounds(
+ bounds: &Punctuated<TypeParamBound, Token![+]>,
+ ) -> ControlFlow<bool, &Type> {
+ match bounds.last().unwrap() {
+ TypeParamBound::Trait(t) => last_type_in_path(&t.path),
+ TypeParamBound::Lifetime(_)
+ | TypeParamBound::PreciseCapture(_)
+ | TypeParamBound::Verbatim(_) => ControlFlow::Break(false),
+ }
+ }
+}
+
+/// Whether the expression's first token is the label of a loop/block.
+#[cfg(all(feature = "printing", feature = "full"))]
+pub(crate) fn expr_leading_label(mut expr: &Expr) -> bool {
+ loop {
+ match expr {
+ Expr::Block(e) => return e.label.is_some(),
+ Expr::ForLoop(e) => return e.label.is_some(),
+ Expr::Loop(e) => return e.label.is_some(),
+ Expr::While(e) => return e.label.is_some(),
+
+ Expr::Assign(e) => expr = &e.left,
+ Expr::Await(e) => expr = &e.base,
+ Expr::Binary(e) => expr = &e.left,
+ Expr::Call(e) => expr = &e.func,
+ Expr::Cast(e) => expr = &e.expr,
+ Expr::Field(e) => expr = &e.base,
+ Expr::Index(e) => expr = &e.expr,
+ Expr::MethodCall(e) => expr = &e.receiver,
+ Expr::Range(e) => match &e.start {
+ Some(start) => expr = start,
+ None => return false,
+ },
+ Expr::Try(e) => expr = &e.expr,
+
+ Expr::Array(_)
+ | Expr::Async(_)
+ | Expr::Break(_)
+ | Expr::Closure(_)
+ | Expr::Const(_)
+ | Expr::Continue(_)
+ | Expr::Group(_)
+ | Expr::If(_)
+ | Expr::Infer(_)
+ | Expr::Let(_)
+ | Expr::Lit(_)
+ | Expr::Macro(_)
+ | Expr::Match(_)
+ | Expr::Paren(_)
+ | Expr::Path(_)
+ | Expr::RawAddr(_)
+ | Expr::Reference(_)
+ | Expr::Repeat(_)
+ | Expr::Return(_)
+ | Expr::Struct(_)
+ | Expr::TryBlock(_)
+ | Expr::Tuple(_)
+ | Expr::Unary(_)
+ | Expr::Unsafe(_)
+ | Expr::Verbatim(_)
+ | Expr::Yield(_) => return false,
+ }
+ }
+}
+
+/// Whether the expression's last token is `}`.
+#[cfg(feature = "full")]
+pub(crate) fn expr_trailing_brace(mut expr: &Expr) -> bool {
+ loop {
+ match expr {
+ Expr::Async(_)
+ | Expr::Block(_)
+ | Expr::Const(_)
+ | Expr::ForLoop(_)
+ | Expr::If(_)
+ | Expr::Loop(_)
+ | Expr::Match(_)
+ | Expr::Struct(_)
+ | Expr::TryBlock(_)
+ | Expr::Unsafe(_)
+ | Expr::While(_) => return true,
+
+ Expr::Assign(e) => expr = &e.right,
+ Expr::Binary(e) => expr = &e.right,
+ Expr::Break(e) => match &e.expr {
+ Some(e) => expr = e,
+ None => return false,
+ },
+ Expr::Cast(e) => return type_trailing_brace(&e.ty),
+ Expr::Closure(e) => expr = &e.body,
+ Expr::Let(e) => expr = &e.expr,
+ Expr::Macro(e) => return e.mac.delimiter.is_brace(),
+ Expr::Range(e) => match &e.end {
+ Some(end) => expr = end,
+ None => return false,
+ },
+ Expr::RawAddr(e) => expr = &e.expr,
+ Expr::Reference(e) => expr = &e.expr,
+ Expr::Return(e) => match &e.expr {
+ Some(e) => expr = e,
+ None => return false,
+ },
+ Expr::Unary(e) => expr = &e.expr,
+ Expr::Verbatim(e) => return tokens_trailing_brace(e),
+ Expr::Yield(e) => match &e.expr {
+ Some(e) => expr = e,
+ None => return false,
+ },
+
+ Expr::Array(_)
+ | Expr::Await(_)
+ | Expr::Call(_)
+ | Expr::Continue(_)
+ | Expr::Field(_)
+ | Expr::Group(_)
+ | Expr::Index(_)
+ | Expr::Infer(_)
+ | Expr::Lit(_)
+ | Expr::MethodCall(_)
+ | Expr::Paren(_)
+ | Expr::Path(_)
+ | Expr::Repeat(_)
+ | Expr::Try(_)
+ | Expr::Tuple(_) => return false,
+ }
+ }
+
+ fn type_trailing_brace(mut ty: &Type) -> bool {
+ loop {
+ match ty {
+ Type::BareFn(t) => match &t.output {
+ ReturnType::Default => return false,
+ ReturnType::Type(_, ret) => ty = ret,
+ },
+ Type::ImplTrait(t) => match last_type_in_bounds(&t.bounds) {
+ ControlFlow::Break(trailing_brace) => return trailing_brace,
+ ControlFlow::Continue(t) => ty = t,
+ },
+ Type::Macro(t) => return t.mac.delimiter.is_brace(),
+ Type::Path(t) => match last_type_in_path(&t.path) {
+ Some(t) => ty = t,
+ None => return false,
+ },
+ Type::Ptr(t) => ty = &t.elem,
+ Type::Reference(t) => ty = &t.elem,
+ Type::TraitObject(t) => match last_type_in_bounds(&t.bounds) {
+ ControlFlow::Break(trailing_brace) => return trailing_brace,
+ ControlFlow::Continue(t) => ty = t,
+ },
+ Type::Verbatim(t) => return tokens_trailing_brace(t),
+
+ Type::Array(_)
+ | Type::Group(_)
+ | Type::Infer(_)
+ | Type::Never(_)
+ | Type::Paren(_)
+ | Type::Slice(_)
+ | Type::Tuple(_) => return false,
+ }
+ }
+ }
+
+ fn last_type_in_path(path: &Path) -> Option<&Type> {
+ match &path.segments.last().unwrap().arguments {
+ PathArguments::None | PathArguments::AngleBracketed(_) => None,
+ PathArguments::Parenthesized(arg) => match &arg.output {
+ ReturnType::Default => None,
+ ReturnType::Type(_, ret) => Some(ret),
+ },
+ }
+ }
+
+ fn last_type_in_bounds(
+ bounds: &Punctuated<TypeParamBound, Token![+]>,
+ ) -> ControlFlow<bool, &Type> {
+ match bounds.last().unwrap() {
+ TypeParamBound::Trait(t) => match last_type_in_path(&t.path) {
+ Some(t) => ControlFlow::Continue(t),
+ None => ControlFlow::Break(false),
+ },
+ TypeParamBound::Lifetime(_) | TypeParamBound::PreciseCapture(_) => {
+ ControlFlow::Break(false)
+ }
+ TypeParamBound::Verbatim(t) => ControlFlow::Break(tokens_trailing_brace(t)),
+ }
+ }
+
+ fn tokens_trailing_brace(tokens: &TokenStream) -> bool {
+ if let Some(TokenTree::Group(last)) = tokens.clone().into_iter().last() {
+ last.delimiter() == Delimiter::Brace
+ } else {
+ false
+ }
+ }
+}