profile
viewpoint
Bryan Cantrill bcantrill Oxide Computer Company dtrace.org/blogs/bmc

bcantrill/node-libdtrace 101

libdtrace bindings for node.js

bcantrill/node-libGeoIP 10

node.js addon for libGeoIP

bcantrill/bfuld 3

Modifies an ELF interpreter for development purposes

bcantrill/node-geoip 3

Naive wrapper around libGeoIP for use with node.js

bcantrill/node 2

evented I/O for v8 javascript

bcantrill/node-dtrace-provider 1

Native DTrace probes for node.js apps

bcantrill/statemap 1

Software for rendering statemaps

bcantrill/concatjson 0

concatenated JSON streaming parser/serializer for node.js

bcantrill/engmeetup-2017-lightning-talk 0

Lightning talk for Joyent Engineering Meetup 2017

pull request commentmbedmicro/pyOCD

many fixes for ITM/SWO/SWV

Did you want to fix the "DAP_VENDOR0" log message before I merged?

Yes, fixed that -- thanks for spotting it!

bcantrill

comment created time in 21 days

push eventoxidecomputer/pyOCD

Bryan Cantrill

commit sha f1f37c99925f17864bcdc85db894d634523d1fa0

DAP_VENDOR device error should include vendor ID

view details

push time in 21 days

pull request commentmbedmicro/pyOCD

many fixes for ITM/SWO/SWV

Thanks. It did actually work at one point, but I was primarily using it without the gdbserver in custom scripts. It was partially merged upstream just so it didn't completely rot on a branch somewhere, and so hopefully someone would find it useful and help improve. Your work here is very much appreciated.

Happy to help! Glad that we were able to get it all working. For whatever it's worth, the multithreaded nature of pyOCD means that you definitely want to test the GDB server concurrently with the SWO reader, as that was the source of several of these issues. But this is hard to test in any automated fashion, and definitely has a significant MCU- and probe-specific component; it's an impossibly big matrix, in many ways.

bcantrill

comment created time in 21 days

Pull request review commentmbedmicro/pyOCD

many fixes for ITM/SWO/SWV

 def _request__get_memory_interface_for_ap(self, ap_address_version, ap_nominal_a             handle = None         return handle     +    def _request__swo_read(self):+        return list(self._probe.swo_read())

I was trying to keep with what appeared to be the intended signature in the comments of returning a list of integers.

bcantrill

comment created time in 21 days

PullRequestReviewEvent
PullRequestReviewEvent

Pull request review commentmbedmicro/pyOCD

many fixes for ITM/SWO/SWV

 def __init__(self, session, core=None, server_listening_callback=None):         # Read back bound port in case auto-assigned (port 0)         self.port = self.abstract_socket.port +        # Coarse grain lock to synchronize SWO with other activity+        self.lock = threading.Lock()

The DebugProbe class locks are too fine-grained, unfortunately.

bcantrill

comment created time in 21 days

Pull request review commentmbedmicro/pyOCD

many fixes for ITM/SWO/SWV

 def vendor(self, index, data):          if resp[0] != Command.DAP_VENDOR0 + index:             # Response is to a different command-            raise DAPAccessIntf.DeviceError()+            raise DAPAccessIntf.DeviceError("expected DAP_VENDOR0")

Agreed; good catch.

bcantrill

comment created time in 21 days

PullRequestReviewEvent

Pull request review commentmbedmicro/pyOCD

many fixes for ITM/SWO/SWV

 def receive(self, event):         """         if not isinstance(event, TraceITMEvent):             return-        -        if not event.port == 0:-            return-        +

The use of a particular port for a particular purpose is entirely based on convention, not definition. Making it configurable would be fine, though I would leave that to subsequent work.

bcantrill

comment created time in 21 days

PullRequestReviewEvent

Pull request review commentmbedmicro/pyOCD

many fixes for ITM/SWO/SWV

 def __init__(self, session, core=None, server_listening_callback=None):             semihost_console = semihost_io_handler         self.semihost = semihost.SemihostAgent(self.target_context, io_handler=semihost_io_handler, console=semihost_console)         +        #+        # If SWV is enabled, create a SWVReader thread. Note that we only do+        # this if the core is 0: SWV is not a per-core construct, and can't+        # be meaningfully read by multiple threads concurrently.+        #         self._swv_reader = None-        if session.options.get("enable_swv"):++        if session.options.get("enable_swv") and core == 0:

Yes, though the right fix is to have the SWVReader not have any notion of core whatsoever, and to handle core-based event handling at a different layer -- but I was trying to get this working with minimal change, not rearchitect it.

bcantrill

comment created time in 21 days

PullRequestReviewEvent

pull request commentmbedmicro/pyOCD

many fixes for ITM/SWO/SWV

Questions/comments:

Locking I'm really curious what interactions between the gdbserver and SWV thread caused issues. The existing locks seem like they should take care of it. Although, these locks were only merged in (ed54d26) on June 18, this year, and released in v0.27.0.

  • All DebugProbe instances have a lock accessible by lock() and unlock() methods. This is used by the DP code to serialize all DP/AP register accesses.
  • MEM_AP has its own lock for all memory transactions performed on that AP.
  • DAPAccessCMSISDAP serializes the SWO commands with other CMSIS-DAP commands.

I did all of my testing on latest, for whatever it's worth. SWO commands do not, unfortunately, serialize with all other CMSIS-DAP commands: because the locking is so fine-grained, there is nothing to prevent (say) read_reg from being interfered with by a swo_read in the (large) window between writing to and reading from the interface.

It should also be noted that this really didn't work at all (threads immediately die with data corruption as they start to interfere with one another) -- to the point that it's hard to believe that anyone has really tested SWO on CMSIS-DAP. So this should be immediately reproducible for anyone connecting GDB to a target that has SWO enabled (as described by @adamgreig in #855), should you be interested in the specific failure modes.

bcantrill

comment created time in 21 days

PR opened mbedmicro/pyOCD

many fixes for ITM/SWO/SWV

This work addresses a total of 9 issues that were preventing ITM + SWO from working on pyOCD + LPC55S69 + CMSIS-DAP. Some of these are particular to our use case, but many are generic to pyOCD + SWO.

  1. When ITM is enabled, TPR is incorrectly modified to disable unprivileged writes when it intended the exact opposite, causing unprivileged stimulus writes to be silently dropped. This work modifies TPR as intended: to allow all unprivileged stimulus writes.

  2. The remote probe interface doesn't correctly return SWO data; the swo_read fails on a bad JSON encoding. This work correctly returns a list of integers representing bytes.

  3. On CMSIS-DAP, when enabling SWO when SWO is already enabled, SWO is not first disabled, causing subsequent configuration to fail and the SWO reader to malfunction. This work always disables SWO before configuring it.

  4. On CMSIS-DAP, the size sent in a DAP_SWO_DATA request does not correctly adjust for the protocol overhead, potentially causing the last four bytes of the SWO packet to be left unread. These trailing bytes will then be read on a subsequent read, causing an exception when the data payload does not constitute the expected bytes. This work adjusts the size sent in DAP_SWO_DATA to reflect the protocol overhead.

  5. On CMSIS-DAP, both CommandError and DeviceError are constructed without error messages, making it hard to debug failures from a stack trace. This work modifies the construction of these errors to always specify an error message.

  6. For reasons that are unclear, the SWO parser silently drops any ITM instrumentation packet for any stimulus port other than port 0. This work modifies the SWO parser to not drop any ITM packets.

  7. The GDB server creates a separate SWO reader for each core (even though there is nothing core-specific with respect to SWO). Because there is no locking between these threads, having multiple threads reading SWO causes more or less causes rampant corruption of the ITM stream on multicore targets. This work creates only a single SWO reader thread, regardless of the number of cores.

  8. There is no serialization between the SWO reader thread and the GDB server. As a result, if SWO and GDB are both simultaneously active, both the SWO reader and the GDB server are likely to experience protocol errors. (This is likely the cause of issue #855.) This work adds a very coarse grain locking scheme between the two to assure that only one thread is talking to the underlying probe at at a time.

  9. On the LPC55, resets with SWO enabled will cause ITM stimulus writes in the target to hang: because ITM is enabled but TRACECLKDIV and TRACECLKSEL are reset, the stimulus port is not disabled but the FIFO never becomes ready. This work explicitly sets TRACECLKDIV and TRACECLKSEL on a reset on the LPC55.

+100 -49

0 comment

8 changed files

pr created time in 22 days

push eventoxidecomputer/pyOCD

Bryan Cantrill

commit sha d3f1e2999c0af44ca6f57e32e5af03ba126c6433

many fixes for ITM/SWO/SWV This work addresses a total of 9 issues that were preventing ITM + SWO from working on pyOCD + LPC55S69 + CMSIS-DAP. Some of these are particular to our use case, but many are generic to pyOCD + SWO. 1. When ITM is enabled, TPR is incorrectly modified to *disable* unprivileged writes when it intended the exact opposite, causing unprivileged stimulus writes to be silently dropped. This work modifies TPR as intended: to allow all unprivileged stimulus writes. 2. The remote probe interface doesn't correctly return SWO data; the swo_read fails on a bad JSON encoding. This work correctly returns a list of integers representing bytes. 3. On CMSIS-DAP, when enabling SWO when SWO is already enabled, SWO is not first disabled, causing subsequent configuration to fail and the SWO reader to malfunction. This work always disables SWO before configuring it. 4. On CMSIS-DAP, the size sent in a DAP_SWO_DATA request does not correctly adjust for the protocol overhead, potentially causing the last four bytes of the SWO packet to be left unread. These trailing bytes will then be read on a subsequent read, causing an exception when the data payload does not constitute the expected bytes. This work adjusts the size sent in DAP_SWO_DATA to reflect the protocol overhead. 5. On CMSIS-DAP, both CommandError and DeviceError are constructed without error messages, making it hard to debug failures from a stack trace. This work modifies the construction of these errors to always specify an error message. 6. For reasons that are unclear, the SWO parser silently drops any ITM instrumentation packet for any stimulus port other than port 0. This work modifies the SWO parser to not drop any ITM packets. 7. The GDB server creates a separate SWO reader for each core (even though there is nothing core-specific with respect to SWO). Because there is no locking between these threads, having multiple threads reading SWO causes more or less causes rampant corruption of the ITM stream on multicore targets. This work creates only a single SWO reader thread, regardless of the number of cores. 8. There is no serialization between the SWO reader thread and the GDB server. As a result, if SWO and GDB are both simultaneously active, both the SWO reader and the GDB server are likely to experience protocol errors. (This is likely the cause of issue #855.) This work adds a very coarse grain locking scheme between the two to assure that only one thread is talking to the underlying probe at at a time. 9. On the LPC55, resets with SWO enabled will cause ITM stimulus writes in the target to hang: because ITM is enabled but TRACECLKDIV and TRACECLKSEL are reset, the stimulus port is not disabled but the FIFO never becomes ready. This work explicitly sets TRACECLKDIV and TRACECLKSEL on a reset on the LPC55.

view details

push time in 22 days

push eventoxidecomputer/pyOCD

Chris Reed

commit sha d5a2a96cf6bd0ac35bdbe1100c6ca6db8bec5988

Fix target types for STM32 boards with CMSIS-Pack based target support.

view details

Chris Reed

commit sha ec6d9539358efca2bd3d9d57b89ec62b25e83769

Merge pull request #915 from flit/bugfix/stm32_board_targets Fix target types for STM32 boards with CMSIS-Pack based target support

view details

Chris Reed

commit sha 67660a1aebc15428dccaaf4826490d8a6201b5b4

DFP: fix more ridiculous bugs in flash region generation.

view details

Chris Reed

commit sha 4b48826cfe5205509c802d119a000bfc796a2f36

Merge pull request #919 from flit/bugfix/dfp_flash_regions Fix more bugs in DFP flash region generation

view details

Bohdan Tymkiv

commit sha 2015c26461447910bceb23a5491a29124bd5dff2

PSoC64: Use S25Hx512T SMIF loader for full_flash targets

view details

Chris Reed

commit sha 8ed4d65d41040a6950c49f43400a3c4099932a13

Merge pull request #920 from bohdan-tymkiv/psoc64-1m-fixes PSoC64: Fix SMIF flash algorithm type for cy8c64xx_cmX_full_flash targets

view details

Chris Reed

commit sha 6ba6ba3c49fa6d70416a3db4d1e3b767503cc422

Docs: more API examples for opening sessions.

view details

Chris Reed

commit sha c0c66951402e8d58662723e72fcaae2f269478a6

Correct doc comment for InternalError.

view details

Chris Reed

commit sha faf48e0071066a3c5bb527be98c2511193d0a15a

Gdbserver: Fix catch-all exception handler.

view details

Chris Reed

commit sha 1ef03ea2bc1b9e84d3f007767e20d43f9c1e7789

Merge pull request #922 from flit/bugfix/gdbserver_catch_all Gdbserver: Fix catch-all exception handler.

view details

Chris Reed

commit sha 4caa9fbd1dfd0744780e6168e283b72bff590ab1

Support for probe and RTOS plugins. - Replaced explicit lists of probe and RTOS classes with plugins that are defined by pkg_resources entry points. This allows other python packages to add plugins for pyocd. - Plugins vend a subclass of Plugin, which has common properties and methods. A plugin is asked whether it can load, and loading returns the implementation class or other object. - Plugins can provide a list of options that are added to the builtin options when the plugin is loaded. - Restructured builtin options to be loaded using the same method as plugin options. - Added Plugin classes and entry points in setup.py for builtin plugins. - Moved JLink probe options to the JLink plugin. - Extended json and list subcommands to report on available plugins.

view details

Chris Reed

commit sha 975073ca1b0e49d1dc50cf03b4b7e484504cace6

Debug probes: Add optional probe type field to unique ID. - Allows specifying which probe class to use by prefixing the unique ID with "<probe-type>:", where probe-type is the name of the pyocd.probe plugin. - Added unique_id and is_explicit parameters to probe query APIs.

view details

Chris Reed

commit sha cb2f9396fae126970659028443fed7c12b42e2da

Test: fix expected features JSON version in gdb_server_json_test.py.

view details

Chris Reed

commit sha 5c90e5f169abd7779373135ac788a89c9ed4d854

pywinusb backend: raise DeviceError on timeout while opening device. - DeviceError is raised instead of a forced assertion failure.

view details

Chris Reed

commit sha dedadc84ee764792835c09da6912cffb1b4834c1

SWJ: renamed swj options and inverted deprecated/dormant switch. - Fixed mismatch between dap_swj_* options that were renamed. - Changed SWJSequenceSender use_deprecated property to use_dormant. - Updated docs.

view details

Chris Reed

commit sha eb2c72949b865dbf26151e41b0910f3cb0f96175

Merge pull request #891 from flit/feature/plugins Debug probe and RTOS plugin support

view details

Chris Reed

commit sha c1bdff9128685aa7a20b26aa5a9efbab218a86b7

CortexM: added SecureFault vector catch.

view details

Chris Reed

commit sha 4e7784f833c4d0338d848d2a30dd144f9d079df6

CortexM: extensions property. - Defined enums for all extensions through v8.1-M, but only the extensions identified by existing code are added: FPU, FPU_DP, SEC.

view details

Chris Reed

commit sha 528bd359e08b612a0c44e57a23c0a2904a820bd4

CortexM: use 'reset.halt_timeout' option in reset and halt.

view details

Chris Reed

commit sha ef704a82cdd50d1acaa3fbab380689771bc352d5

CortexM: use the Cortex-M system address map if no memory map is provided.

view details

push time in 22 days

startedezrosent/frawk

started time in a month

issue commentrust-num/num-derive

derives panic when a discriminant is given by a macro

Thanks for opening this back up! The failure mode was indeed really confusing -- but your new error message is great, and would have sent me to the right spot more or less immediately; thanks again!

AdnoC

comment created time in 2 months

issue commentrust-num/num-derive

derives panic when a discriminant is given by a macro

I hit this as well -- thank you @AdnoC and @cuviper for what ended up being a quick fix to an otherwise vexing problem! Was there ever an issue open on syn? If not, I think I'd like to get an issue open over there (and/or commented upon); the failure mode here is pretty brutal...

AdnoC

comment created time in 2 months

issue openedprobe-rs/probe-rs

write batching can cause run() to return while core is still halted

With #221, batched writes were introduced for DAPLink. This is a huge performance win, but it relies on reads (or a detach) to actually issue any batched writes. Normally, this isn't an issue, as many writes are often followed by reads to observe changed state. However, there are classes of writes that In particular, run() will issue only writes; if those writes are batched, control flow will return to the caller without the core being, in fact, resumed. In discussing this issue with @adamgreig and @Yatekii, we agreed that the best way to fix this would be to introduce a flush operation on the Core, exporting that to users of Core and calling it explicitly in the run implementations. Here is a prototype that implements this:

https://github.com/oxidecomputer/probe-rs/commit/a12a8ffc0d537fb74d31fc5dc1e763a5deda9fc8

This approach seemed to work well; assuming others agree, once itm lands (see #256), happy to turn this into a PR...

created time in 2 months

push eventoxidecomputer/probe-rs

Bryan Cantrill

commit sha a12a8ffc0d537fb74d31fc5dc1e763a5deda9fc8

introduce operation to flush any batched writes With probe's batching writes, there is a need for higher-level software to flush any buffered writes. This assures that (say) operations like run() do not run the risk of returning to the caller with their operations not sent to the MCU. (This issue was the reason for failures in SWO processing on the LPC55, as higher level software's resume of the halted part was not, in fact, resuming the part.)

view details

push time in 2 months

push eventoxidecomputer/probe-rs

Noah Hüsser

commit sha a259c685c3551c5f5c1f4834903c3bda0c2bcdf2

Fix serialization

view details

Noah Hüsser

commit sha 626d9114bdb6c8aa7645109a5afb7e1254130441

Add a test to test successfull serialization to prevent further breakage

view details

Henrik Böving

commit sha 46466f6971666a29fb90df082623d2d7aafd60d5

Performance and functionality improvements for gdb (#236) * Performance and functionality improvements for gdb * Make the endlessly polling function await_halt in worker.rs sleep for 1ms on every iteration so we don't constantly draw 100 % from the CPU core we're running on * Return a T02 instead of a T05hwbreak when a user requests a break via an interrupt with Ctrl-c (stolen from OpenOCD, I don't actually know the meaning of the 02) * Previously await_halt would send a constant stream of T05hwbreak to the GDB client once the core was haltet as await_halt was never set to false when a breakpoint was hit, change this behaviour so breaking actually works.

view details

Henrik Böving

commit sha 43858fb8e76a7b040cdbfc2a25936114023a1591

CHANGELOG for the gdb-server fixes (#237) * Update CHANGELOG.md with the gdb-server fixes Co-Authored-By: Yatekii <Yatekii@users.noreply.github.com>

view details

Noah Hüsser

commit sha 61fc04d51707aec185958df9d01d9b11224209eb

WIP: Base impl done

view details

Dominik Boehi

commit sha 0031986157544621f9b4ff98341fa5952241e40f

Fix broken vCont and memory-map, add LLDB support LLDB is using some different commands, which we don't support (yet). It gets confused when we reply with 'OK' to these, so we just send an empty response now. With these changes, LLDB seems to work pretty well. See also: https://github.com/llvm/llvm-project/blob/master/lldb/docs/lldb-gdb-remote.txt

view details

Noah Hüsser

commit sha f50365d4b07c7b2c3ffe6b94e6c04653ebc63971

Applications are adjusted and Riscv fully enabled; Core state is now stored properly

view details

Noah Hüsser

commit sha 6993d6b6d4ff7a35cea97634bb0a624d3006d2e0

Fixed warnings

view details

Noah Hüsser

commit sha 86b21c87725d41b457708702d7911d69649be0a3

Hopefully fix recursion

view details

Noah Hüsser

commit sha b351bc1132d0ff7fee26d32af6342ed9683cf040

Fix a doctest; second one to be fixed

view details

Dominik Boehi

commit sha b3a1e299ea9a313eae2b5a9dd186f9c648d07f41

Support for RISCV Flashloader

view details

Dominik Boehi

commit sha db457bbe9e86c734970ce92859a81b2a5c9e1fd0

Improve memory read/write speed for RISCV

view details

Dominik Boehi

commit sha 12615f9ad739591b09e27448758e310a8ec65aff

Adress review feedback

view details

Noah Hüsser

commit sha 0c6bd36b9da4961afeb6ea359543fa271326b104

Clean up lifetimes with properly naming them for better tracking and removing unneeded ones

view details

Noah Hüsser

commit sha caf59cf955cb0f7156ea447b9fa7225fdf502b69

Address some feedback

view details

Noah Hüsser

commit sha 82c832bdb3118b9aa7bc444b0fbd91794a5df876

Make the inner core state persistent

view details

Noah Hüsser

commit sha 07295326f37d7dda744541fa633c7e825c49295b

Fix doctests and also rename the two attach functions

view details

Noah Hüsser

commit sha dcce4135f8e111efb90dcef488296bb21f6082fe

Merge branch 'master' into api-changes

view details

Noah Hüsser

commit sha 1da8e455156056c7c57681488ad0aada7b14cf37

Revert auto_attach rename

view details

Noah Hüsser

commit sha a485eb40daaed9c96deba9c6a3d705ac852479e6

Make the M cores only poll the state on first construction

view details

push time in 2 months

startedprobe-rs/hs-probe-firmware

started time in 2 months

startedheadcrab-rs/headcrab

started time in 2 months

issue openedrust-lang/rust

using inner tool attributes in crate root induces compiler error on intra-crate macro use

Take a crate that has the following foo.rs, that contains a macro, foomacro()!:

#[macro_export]
macro_rules! foomacro {
    ($f:expr) => ({
        println!("foomacro: {}", $f);
    });
}

This macro is used in bar.rs:

use crate::foomacro;

pub fn bar() {
    foomacro!("bar");
}

Finally, here is the root of the crate and main.rs:

#![feature(custom_inner_attributes)]

// Setting any inner tool attribute here causes a compiler error on bar's use of
// foomacro!():
//
//   error: macro-expanded `macro_export` macros from the current crate cannot
//   be referred to by absolute paths
//
// To see this, uncomment either of the following lines:
//
// #![clippy::cyclomatic_complexity = "100"]
// #![rustfmt::skip]

mod foo;
mod bar;

fn main() {
    foomacro!("foo");
    bar::bar();
}

As the comment there indicates, as written, this compiles and runs as expected:

$ cargo run
   Compiling modmac v0.1.0 (/home/bmc/modmac)
    Finished dev [unoptimized + debuginfo] target(s) in 0.18s
     Running `target/debug/modmac`
foomacro: foo
foomacro: bar

If, however, either of the inner tool attributes is uncommented, the code fails on compiling bar.rs, complaining about its use of foomacro()!

$ cargo run
   Compiling modmac v0.1.0 (/home/bmc/modmac)
error: macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths
 --> src/bar.rs:2:5
  |
2 | use crate::foomacro;
  |     ^^^^^^^^^^^^^^^
  |
  = note: `#[deny(macro_expanded_macro_exports_accessed_by_absolute_paths)]` on by default
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
  = note: for more information, see issue #52234 <https://github.com/rust-lang/rust/issues/52234>
note: the macro is defined here
 --> src/foo.rs:2:1
  |
2 | / macro_rules! foomacro {
3 | |     ($f:expr) => ({
4 | |         println!("foomacro: {}", $f);
5 | |     });
6 | | }
  | |_^

error: aborting due to previous error

error: could not compile `modmac`.

This behavior seems surprising, especially because tool attributes are generally thought to only be relevant to the specified tool:

When a tool is not in use, the tool's attributes are accepted without a warning. When the tool is in use, the tool is responsible for processing and interpretation of its attributes.

Thanks in advance for any consideration of this issue -- and apologies if this is an elaborate form of pilot error!

created time in 3 months

push eventoxidecomputer/probe-rs

Bryan Cantrill

commit sha 7ae63a56ec8124790fa520d84fcb505bca7cbb8e

eliminate spurious warning on step()

view details

push time in 3 months

issue openedrust-lang/rustfmt

allow optional programmer discretion on chain length/function arguments per line

When lines hit max_width (or its derivatives), rustfmt will break chains and function calls with one call or argument per line. We have found this to result in code that is less clear, and no more consistent with Rust's style than the code that it replaces. We would like to see an option whereby these chains and function calls would be left to programmer discretion as long as they observe the constraints of indentation and max_width.

To make this more concrete, we have experienced this most recently in the embedded Rust world, where hardware-abstracting crates make extensive use of types to constrain context (viz. <a href="https://docs.rs/svd2rust/0.17.0/svd2rust/#read--modify--write-api">svd2rust's API</a>).

The upshot of this is that we end up with long chains that are asymmetric in that different positions in the chain actually denote different states. Often, the programmer will use the line break to help clarify what's going on; some (real) examples:

fn func() {
    p.RCC.pllcfgr.modify(|_, w| {
        w.pll1vcosel().wide_vco()
            .pll1rge().range8()
            .divp1en().enabled()
            .divq1en().enabled()
            .divr1en().enabled()
    });

    p.RCC.d1cfgr.write(|w| {
        w.d1cpre().div1()
            .d1ppre().div1()
            .hpre().div1()
    });
}

In this case, the programmer has clearly grouped the chain to indicate the type states -- and to the reader, both uses are clear. rustfmt, however, doesn't like either of these expressions; they get reformatted as:

fn func() {
    p.RCC.pllcfgr.modify(|_, w| {
        w.pll1vcosel()
            .wide_vco()
            .pll1rge()
            .range8()
            .divp1en()
            .enabled()
            .divq1en()
            .enabled()
            .divr1en()
            .enabled()
    });

    p.RCC
        .d1cfgr
        .write(|w| w.d1cpre().div1().d1ppre().div1().hpre().div1());
}

In both cases, meaning has been lost -- even though the code as written is consistent with Rust's style. We can of course wrap these constructs in #[rustfmt skip] -- but they come up often enough that we would very much rather fix it in rustfmt. And to be clear, we don't want these to be compressed either (as raised in #4146 and <a href="https://github.com/rust-lang/rustfmt/issues/2010">#2010</a>); we seek to have them be optionally left to the programmer's discretion, within the bounds of the configured style.

Thank you in advance for your consideration and your work on this essential (if underappreciated!) part of the Rust ecosystem!

cc: @cbiffle @steveklabnik @davepacheco @ahl

created time in 3 months

more