Skip to content

unreachable_code warning when using tailcall #19

Open
@SichangHe

Description

@SichangHe

I am trying out this library and it seems to work perfectly, except that there is a compile-time unreachable_code warning coming from I-don't-know where.

Warning message

$ RUSTFLAGS="-Zmacro-backtrace" cargo +nightly c
…
  --> src/paragraphs.rs:58:1
   |
58 | #[tailcall]
   | ^^^^^^^^^^^
   | |
   | unreachable expression
   | any code following this expression is unreachable
   | in this procedural macro expansion
   |
  ::: /Users/sichanghe/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tailcall-impl-1.0.1/src/lib.rs:94:1
   |
94 | pub fn tailcall(_attr: TokenStream, tokens: TokenStream) -> TokenStream {
   | ----------------------------------------------------------------------- in this expansion of `#[tailcall]`
   |
   = note: `#[warn(unreachable_code)]` on by default

Source code

#[inline(always)]
#[tailcall]
fn iter_inner_next<'a>(
    iter: &mut ParagraphsIter<'a>,
    indentation: usize,
    next_new_line_index: usize,
) -> Option<Paragraph<'a>> {
    let following_text = &iter.text[next_new_line_index..];
    trace!(following_text, next_new_line_index);
    let mut ignore = false;

    // NB: Side effect blocks can be short-circuited.
    if following_text.is_empty()
        || following_text.starts_with('\n')
        || (!iter.allow_indented_paragraphs
            && first_line_indentation(following_text) != indentation)
        || (iter.next_is_ignore_paragraph && next_new_line_index > 0 && {
            ignore = true;
            iter.next_is_ignore_paragraph = false;
            true
        })
        || (iter.paragraph_starts.ignore_line_matches(following_text) && {
            iter.next_is_ignore_paragraph = true;
            next_new_line_index != 0
        })
        || (iter.next_is_single_paragraph && next_new_line_index > 0 && {
            trace!(next_is_single_paragraph = iter.next_is_single_paragraph);
            iter.next_is_single_paragraph = false;
            true
        })
        || (iter.paragraph_starts.single_line_matches(following_text) && {
            iter.next_is_single_paragraph = true;
            next_new_line_index != 0
        })
        || (next_new_line_index != 0 && iter.paragraph_starts.multi_line_matches(following_text))
    {
        let yielded = Paragraph {
            ignore,
            indentation,
            words: &iter.text[..next_new_line_index],
        };
        iter.text = match next_new_line_index {
            0 => &iter.text[1..], // Yielded an empty paragraph.
            _ => following_text,
        };
        return Some(yielded);
    }

    let line_break_index = following_text
        .find('\n')
        .unwrap_or(following_text.len() - 1);
    iter_inner_next(
        iter,
        indentation,
        next_new_line_index + line_break_index + 1,
    )
}

Expansion output

$ cargo +nightly expand fmtt::paragraph
…
#[inline(always)]
fn iter_inner_next<'a>(
    iter: &mut ParagraphsIter<'a>,
    indentation: usize,
    next_new_line_index: usize,
) -> Option<Paragraph<'a>> {
    let mut tailcall_trampoline_state = (iter, indentation, next_new_line_index);
    'tailcall_trampoline_loop: loop {
        let (iter, indentation, next_new_line_index) = tailcall_trampoline_state;
        return {
            let following_text = &iter.text[next_new_line_index..];
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite = {
                    static META: ::tracing::Metadata<'static> = {
                        ::tracing_core::metadata::Metadata::new(
                            "event src/paragraphs.rs:65",
                            "fmtt::paragraphs",
                            ::tracing::Level::TRACE,
                            ::core::option::Option::Some("src/paragraphs.rs"),
                            ::core::option::Option::Some(65u32),
                            ::core::option::Option::Some("fmtt::paragraphs"),
                            ::tracing_core::field::FieldSet::new(
                                &["following_text", "next_new_line_index"],
                                ::tracing_core::callsite::Identifier(&__CALLSITE),
                            ),
                            ::tracing::metadata::Kind::EVENT,
                        )
                    };
                    ::tracing::callsite::DefaultCallsite::new(&META)
                };
                let enabled = ::tracing::Level::TRACE
                    <= ::tracing::level_filters::STATIC_MAX_LEVEL
                    && ::tracing::Level::TRACE
                        <= ::tracing::level_filters::LevelFilter::current()
                    && {
                        let interest = __CALLSITE.interest();
                        !interest.is_never()
                            && ::tracing::__macro_support::__is_enabled(
                                __CALLSITE.metadata(),
                                interest,
                            )
                    };
                if enabled {
                    (|value_set: ::tracing::field::ValueSet| {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                    })({
                        #[allow(unused_imports)]
                        use ::tracing::field::{debug, display, Value};
                        let mut iter = __CALLSITE.metadata().fields().iter();
                        __CALLSITE
                            .metadata()
                            .fields()
                            .value_set(
                                &[
                                    (
                                        &::core::iter::Iterator::next(&mut iter)
                                            .expect("FieldSet corrupted (this is a bug)"),
                                        ::core::option::Option::Some(&following_text as &dyn Value),
                                    ),
                                    (
                                        &::core::iter::Iterator::next(&mut iter)
                                            .expect("FieldSet corrupted (this is a bug)"),
                                        ::core::option::Option::Some(
                                            &next_new_line_index as &dyn Value,
                                        ),
                                    ),
                                ],
                            )
                    });
                } else {
                }
            };
            let mut ignore = false;
            if following_text.is_empty() || following_text.starts_with('\n')
                || (!iter.allow_indented_paragraphs
                    && first_line_indentation(following_text) != indentation)
                || (iter.next_is_ignore_paragraph && next_new_line_index > 0
                    && {
                        ignore = true;
                        iter.next_is_ignore_paragraph = false;
                        true
                    })
                || (iter.paragraph_starts.ignore_line_matches(following_text)
                    && {
                        iter.next_is_ignore_paragraph = true;
                        next_new_line_index != 0
                    })
                || (iter.next_is_single_paragraph && next_new_line_index > 0
                    && {
                        {
                            use ::tracing::__macro_support::Callsite as _;
                            static __CALLSITE: ::tracing::callsite::DefaultCallsite = {
                                static META: ::tracing::Metadata<'static> = {
                                    ::tracing_core::metadata::Metadata::new(
                                        "event src/paragraphs.rs:83",
                                        "fmtt::paragraphs",
                                        ::tracing::Level::TRACE,
                                        ::core::option::Option::Some("src/paragraphs.rs"),
                                        ::core::option::Option::Some(83u32),
                                        ::core::option::Option::Some("fmtt::paragraphs"),
                                        ::tracing_core::field::FieldSet::new(
                                            &["next_is_single_paragraph"],
                                            ::tracing_core::callsite::Identifier(&__CALLSITE),
                                        ),
                                        ::tracing::metadata::Kind::EVENT,
                                    )
                                };
                                ::tracing::callsite::DefaultCallsite::new(&META)
                            };
                            let enabled = ::tracing::Level::TRACE
                                <= ::tracing::level_filters::STATIC_MAX_LEVEL
                                && ::tracing::Level::TRACE
                                    <= ::tracing::level_filters::LevelFilter::current()
                                && {
                                    let interest = __CALLSITE.interest();
                                    !interest.is_never()
                                        && ::tracing::__macro_support::__is_enabled(
                                            __CALLSITE.metadata(),
                                            interest,
                                        )
                                };
                            if enabled {
                                (|value_set: ::tracing::field::ValueSet| {
                                    let meta = __CALLSITE.metadata();
                                    ::tracing::Event::dispatch(meta, &value_set);
                                })({
                                    #[allow(unused_imports)]
                                    use ::tracing::field::{debug, display, Value};
                                    let mut iter = __CALLSITE.metadata().fields().iter();
                                    __CALLSITE
                                        .metadata()
                                        .fields()
                                        .value_set(
                                            &[
                                                (
                                                    &::core::iter::Iterator::next(&mut iter)
                                                        .expect("FieldSet corrupted (this is a bug)"),
                                                    ::core::option::Option::Some(
                                                        &iter.next_is_single_paragraph as &dyn Value,
                                                    ),
                                                ),
                                            ],
                                        )
                                });
                            } else {
                            }
                        };
                        iter.next_is_single_paragraph = false;
                        true
                    })
                || (iter.paragraph_starts.single_line_matches(following_text)
                    && {
                        iter.next_is_single_paragraph = true;
                        next_new_line_index != 0
                    })
                || (next_new_line_index != 0
                    && iter.paragraph_starts.multi_line_matches(following_text))
            {
                let yielded = Paragraph {
                    ignore,
                    indentation,
                    words: &iter.text[..next_new_line_index],
                };
                iter
                    .text = match next_new_line_index {
                    0 => &iter.text[1..],
                    _ => following_text,
                };
                return Some(yielded);
            }
            let line_break_index = following_text
                .find('\n')
                .unwrap_or(following_text.len() - 1);
            {
                tailcall_trampoline_state = (
                    iter,
                    indentation,
                    next_new_line_index + line_break_index + 1,
                );
                continue 'tailcall_trampoline_loop;
            }
        };
    }
}

P.S. Your README seems to mismatch your current implementation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions