From: bors Date: Sun, 13 Sep 2020 09:18:14 +0000 (+0000) Subject: Auto merge of #76658 - Aaron1011:fix/encode-dummy-loc-span, r=lcnr X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=b6c84553c4fa47174d2510541a90243000fb44d8;hp=a67d248b13e8ac6f83df8994f59e7b89f064339e;p=rust.git Auto merge of #76658 - Aaron1011:fix/encode-dummy-loc-span, r=lcnr Properly encode spans with a dummy location and non-root `SyntaxContext` Previously, we would throw away the `SyntaxContext` of any span with a dummy location during metadata encoding. This commit makes metadata Span encoding consistent with incr-cache Span encoding - an 'invalid span' tag is only used when it doesn't lose any information. --- diff --git a/compiler/rustc/Cargo.toml b/compiler/rustc/Cargo.toml index cf011e63e02..6e6c0c71a1f 100644 --- a/compiler/rustc/Cargo.toml +++ b/compiler/rustc/Cargo.toml @@ -19,3 +19,4 @@ features = ['unprefixed_malloc_on_supported_platforms'] [features] jemalloc = ['jemalloc-sys'] llvm = ['rustc_driver/llvm'] +max_level_info = ['rustc_driver/max_level_info'] diff --git a/compiler/rustc_driver/Cargo.toml b/compiler/rustc_driver/Cargo.toml index 0d9dcb262b2..adfce1008e1 100644 --- a/compiler/rustc_driver/Cargo.toml +++ b/compiler/rustc_driver/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["dylib"] [dependencies] libc = "0.2" -tracing = { version = "0.1.18", features = ["release_max_level_info"] } +tracing = { version = "0.1.18" } tracing-subscriber = { version = "0.2.10", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] } rustc_middle = { path = "../rustc_middle" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } @@ -38,3 +38,4 @@ winapi = { version = "0.3", features = ["consoleapi", "debugapi", "processenv"] [features] llvm = ['rustc_interface/llvm'] +max_level_info = ['tracing/max_level_info'] diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index dedb9850b5a..0becdf24c53 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -364,6 +364,12 @@ fn semantic_tree(tree: &TokenTree) -> bool { | token::CloseDelim(DelimToken::NoDelim) // The pretty printer collapses many semicolons into one. | token::Semi + // We don't preserve leading `|` tokens in patterns, so + // we ignore them entirely + | token::BinOp(token::BinOpToken::Or) + // We don't preserve trailing '+' tokens in trait bounds, + // so we ignore them entirely + | token::BinOp(token::BinOpToken::Plus) // The pretty printer can turn `$crate` into `::crate_name` | token::ModSep = token.kind { return false; diff --git a/config.toml.example b/config.toml.example index 2d5b3136450..39c94d41e3a 100644 --- a/config.toml.example +++ b/config.toml.example @@ -14,6 +14,21 @@ # ============================================================================= [llvm] +# Whether to use Rust CI built LLVM instead of locally building it. +# +# Unless you're developing for a target where Rust CI doesn't build a compiler +# toolchain or changing LLVM locally, you probably want to set this to true. +# +# It's currently false by default due to being newly added; please file bugs if +# enabling this did not work for you on Linux (macOS and Windows support is +# coming soon). +# +# We also currently only support this when building LLVM for the build triple. +# +# Note that many of the LLVM options are not currently supported for +# downloading. Currently only the "assertions" option can be toggled. +#download-ci-llvm = false + # Indicates whether LLVM rebuild should be skipped when running bootstrap. If # this is `false` then the compiler's LLVM will be rebuilt whenever the built # version doesn't have the correct hash. If it is `true` then LLVM will never @@ -322,13 +337,19 @@ # binary, otherwise they are omitted. # # Defaults to rust.debug value -#debug-assertions = false +#debug-assertions = debug # Whether or not debug assertions are enabled for the standard library. # Overrides the `debug-assertions` option, if defined. # # Defaults to rust.debug-assertions value -#debug-assertions-std = false +#debug-assertions-std = debug-assertions + +# Whether or not to leave debug! and trace! calls in the rust binary. +# Overrides the `debug-assertions` option, if defined. +# +# Defaults to rust.debug-assertions value +#debug-logging = debug-assertions # Debuginfo level for most of Rust code, corresponds to the `-C debuginfo=N` option of `rustc`. # `0` - no debug info diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 955c72856dc..44a17f75451 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -14,8 +14,17 @@ import tempfile from time import time - -def get(url, path, verbose=False): +def support_xz(): + try: + with tempfile.NamedTemporaryFile(delete=False) as temp_file: + temp_path = temp_file.name + with tarfile.open(temp_path, "w:xz"): + pass + return True + except tarfile.CompressionError: + return False + +def get(url, path, verbose=False, do_verify=True): suffix = '.sha256' sha_url = url + suffix with tempfile.NamedTemporaryFile(delete=False) as temp_file: @@ -24,19 +33,20 @@ def get(url, path, verbose=False): sha_path = sha_file.name try: - download(sha_path, sha_url, False, verbose) - if os.path.exists(path): - if verify(path, sha_path, False): - if verbose: - print("using already-download file", path) - return - else: - if verbose: - print("ignoring already-download file", - path, "due to failed verification") - os.unlink(path) + if do_verify: + download(sha_path, sha_url, False, verbose) + if os.path.exists(path): + if verify(path, sha_path, False): + if verbose: + print("using already-download file", path) + return + else: + if verbose: + print("ignoring already-download file", + path, "due to failed verification") + os.unlink(path) download(temp_path, url, True, verbose) - if not verify(temp_path, sha_path, verbose): + if do_verify and not verify(temp_path, sha_path, verbose): raise RuntimeError("failed verification") if verbose: print("moving {} to {}".format(temp_path, path)) @@ -365,16 +375,6 @@ class RustBuild(object): cargo_channel = self.cargo_channel rustfmt_channel = self.rustfmt_channel - def support_xz(): - try: - with tempfile.NamedTemporaryFile(delete=False) as temp_file: - temp_path = temp_file.name - with tarfile.open(temp_path, "w:xz"): - pass - return True - except tarfile.CompressionError: - return False - if self.rustc().startswith(self.bin_root()) and \ (not os.path.exists(self.rustc()) or self.program_out_of_date(self.rustc_stamp())): @@ -423,6 +423,19 @@ class RustBuild(object): with output(self.rustfmt_stamp()) as rustfmt_stamp: rustfmt_stamp.write(self.date + self.rustfmt_channel) + if self.downloading_llvm(): + llvm_sha = subprocess.check_output(["git", "log", "--author=bors", + "--format=%H", "-n1"]).decode(sys.getdefaultencoding()).strip() + llvm_assertions = self.get_toml('assertions', 'llvm') == 'true' + if self.program_out_of_date(self.llvm_stamp(), llvm_sha + str(llvm_assertions)): + self._download_ci_llvm(llvm_sha, llvm_assertions) + with output(self.llvm_stamp()) as llvm_stamp: + llvm_stamp.write(self.date + llvm_sha + str(llvm_assertions)) + + def downloading_llvm(self): + opt = self.get_toml('download-ci-llvm', 'llvm') + return opt == "true" + def _download_stage0_helper(self, filename, pattern, tarball_suffix, date=None): if date is None: date = self.date @@ -437,6 +450,25 @@ class RustBuild(object): get("{}/{}".format(url, filename), tarball, verbose=self.verbose) unpack(tarball, tarball_suffix, self.bin_root(), match=pattern, verbose=self.verbose) + def _download_ci_llvm(self, llvm_sha, llvm_assertions): + cache_prefix = "llvm-{}-{}".format(llvm_sha, llvm_assertions) + cache_dst = os.path.join(self.build_dir, "cache") + rustc_cache = os.path.join(cache_dst, cache_prefix) + if not os.path.exists(rustc_cache): + os.makedirs(rustc_cache) + + url = "https://ci-artifacts.rust-lang.org/rustc-builds/{}".format(llvm_sha) + if llvm_assertions: + url = url.replace('rustc-builds', 'rustc-builds-alt') + tarball_suffix = '.tar.xz' if support_xz() else '.tar.gz' + filename = "rust-dev-nightly-" + self.build + tarball_suffix + tarball = os.path.join(rustc_cache, filename) + if not os.path.exists(tarball): + get("{}/{}".format(url, filename), tarball, verbose=self.verbose, do_verify=False) + unpack(tarball, tarball_suffix, self.llvm_root(), + match="rust-dev", + verbose=self.verbose) + def fix_bin_or_dylib(self, fname): """Modifies the interpreter section of 'fname' to fix the dynamic linker, or the RPATH section, to fix the dynamic library search path @@ -558,6 +590,17 @@ class RustBuild(object): """ return os.path.join(self.bin_root(), '.rustfmt-stamp') + def llvm_stamp(self): + """Return the path for .rustfmt-stamp + + >>> rb = RustBuild() + >>> rb.build_dir = "build" + >>> rb.llvm_stamp() == os.path.join("build", "ci-llvm", ".llvm-stamp") + True + """ + return os.path.join(self.llvm_root(), '.llvm-stamp') + + def program_out_of_date(self, stamp_path, extra=""): """Check if the given program stamp is out of date""" if not os.path.exists(stamp_path) or self.clean: @@ -581,6 +624,22 @@ class RustBuild(object): """ return os.path.join(self.build_dir, self.build, "stage0") + def llvm_root(self): + """Return the CI LLVM root directory + + >>> rb = RustBuild() + >>> rb.build_dir = "build" + >>> rb.llvm_root() == os.path.join("build", "ci-llvm") + True + + When the 'build' property is given should be a nested directory: + + >>> rb.build = "devel" + >>> rb.llvm_root() == os.path.join("build", "devel", "ci-llvm") + True + """ + return os.path.join(self.build_dir, self.build, "ci-llvm") + def get_toml(self, key, section=None): """Returns the value of the given key in config.toml, otherwise returns None diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index e0dddda83b9..08907edef1d 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -593,7 +593,7 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS let file = compiler_file(builder, builder.cxx(target).unwrap(), target, "libstdc++.a"); cargo.env("LLVM_STATIC_STDCPP", file); } - if builder.config.llvm_link_shared || builder.config.llvm_thin_lto { + if builder.config.llvm_link_shared { cargo.env("LLVM_LINK_SHARED", "1"); } if builder.config.llvm_use_libcxx { diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 5a79d3db5c9..7c8c729b5bf 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -15,9 +15,20 @@ use crate::cache::{Interned, INTERNER}; use crate::flags::Flags; pub use crate::flags::Subcommand; +use crate::util::exe; use build_helper::t; use serde::Deserialize; +macro_rules! check_ci_llvm { + ($name:expr) => { + assert!( + $name.is_none(), + "setting {} is incompatible with download-ci-llvm.", + stringify!($name) + ); + }; +} + /// Global configuration for the entire build and/or bootstrap. /// /// This structure is derived from a combination of both `config.toml` and @@ -84,6 +95,7 @@ pub struct Config { pub llvm_version_suffix: Option, pub llvm_use_linker: Option, pub llvm_allow_old_toolchain: Option, + pub llvm_from_ci: bool, pub use_lld: bool, pub lld_enabled: bool, @@ -100,6 +112,7 @@ pub struct Config { pub rust_codegen_units_std: Option, pub rust_debug_assertions: bool, pub rust_debug_assertions_std: bool, + pub rust_debug_logging: bool, pub rust_debuginfo_level_rustc: u32, pub rust_debuginfo_level_std: u32, pub rust_debuginfo_level_tools: u32, @@ -344,6 +357,7 @@ struct Llvm { use_libcxx: Option, use_linker: Option, allow_old_toolchain: Option, + download_ci_llvm: Option, } #[derive(Deserialize, Default, Clone)] @@ -379,6 +393,7 @@ struct Rust { codegen_units_std: Option, debug_assertions: Option, debug_assertions_std: Option, + debug_logging: Option, debuginfo_level: Option, debuginfo_level_rustc: Option, debuginfo_level_std: Option, @@ -587,6 +602,7 @@ pub fn parse(args: &[String]) -> Config { let mut debug = None; let mut debug_assertions = None; let mut debug_assertions_std = None; + let mut debug_logging = None; let mut debuginfo_level = None; let mut debuginfo_level_rustc = None; let mut debuginfo_level_std = None; @@ -624,12 +640,50 @@ pub fn parse(args: &[String]) -> Config { set(&mut config.llvm_use_libcxx, llvm.use_libcxx); config.llvm_use_linker = llvm.use_linker.clone(); config.llvm_allow_old_toolchain = llvm.allow_old_toolchain; + config.llvm_from_ci = llvm.download_ci_llvm.unwrap_or(false); + + if config.llvm_from_ci { + // None of the LLVM options, except assertions, are supported + // when using downloaded LLVM. We could just ignore these but + // that's potentially confusing, so force them to not be + // explicitly set. The defaults and CI defaults don't + // necessarily match but forcing people to match (somewhat + // arbitrary) CI configuration locally seems bad/hard. + check_ci_llvm!(llvm.optimize); + check_ci_llvm!(llvm.thin_lto); + check_ci_llvm!(llvm.release_debuginfo); + check_ci_llvm!(llvm.link_shared); + check_ci_llvm!(llvm.static_libstdcpp); + check_ci_llvm!(llvm.targets); + check_ci_llvm!(llvm.experimental_targets); + check_ci_llvm!(llvm.link_jobs); + check_ci_llvm!(llvm.link_shared); + check_ci_llvm!(llvm.clang_cl); + check_ci_llvm!(llvm.version_suffix); + check_ci_llvm!(llvm.cflags); + check_ci_llvm!(llvm.cxxflags); + check_ci_llvm!(llvm.ldflags); + check_ci_llvm!(llvm.use_libcxx); + check_ci_llvm!(llvm.use_linker); + check_ci_llvm!(llvm.allow_old_toolchain); + + // CI-built LLVM is shared + config.llvm_link_shared = true; + } + + if config.llvm_thin_lto { + // If we're building with ThinLTO on, we want to link to LLVM + // shared, to avoid re-doing ThinLTO (which happens in the link + // step) with each stage. + config.llvm_link_shared = true; + } } if let Some(ref rust) = toml.rust { debug = rust.debug; debug_assertions = rust.debug_assertions; debug_assertions_std = rust.debug_assertions_std; + debug_logging = rust.debug_logging; debuginfo_level = rust.debuginfo_level; debuginfo_level_rustc = rust.debuginfo_level_rustc; debuginfo_level_std = rust.debuginfo_level_std; @@ -706,6 +760,20 @@ pub fn parse(args: &[String]) -> Config { } } + if config.llvm_from_ci { + let triple = &config.build.triple; + let mut build_target = config + .target_config + .entry(config.build) + .or_insert_with(|| Target::from_triple(&triple)); + + check_ci_llvm!(build_target.llvm_config); + check_ci_llvm!(build_target.llvm_filecheck); + let ci_llvm_bin = config.out.join(&*config.build.triple).join("ci-llvm/bin"); + build_target.llvm_config = Some(ci_llvm_bin.join(exe("llvm-config", config.build))); + build_target.llvm_filecheck = Some(ci_llvm_bin.join(exe("FileCheck", config.build))); + } + if let Some(ref t) = toml.dist { config.dist_sign_folder = t.sign_folder.clone().map(PathBuf::from); config.dist_gpg_password_file = t.gpg_password_file.clone().map(PathBuf::from); @@ -733,6 +801,8 @@ pub fn parse(args: &[String]) -> Config { config.rust_debug_assertions_std = debug_assertions_std.unwrap_or(config.rust_debug_assertions); + config.rust_debug_logging = debug_logging.unwrap_or(config.rust_debug_assertions); + let with_defaults = |debuginfo_level_specific: Option| { debuginfo_level_specific.or(debuginfo_level).unwrap_or(if debug == Some(true) { 1 diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index e22cdb13928..cf73e570fa5 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -2382,26 +2382,32 @@ fn run(self, builder: &Builder<'_>) { /// Note: This function does not yet support Windows, but we also don't support /// linking LLVM tools dynamically on Windows yet. fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir: &Path) { - let src_libdir = builder.llvm_out(target).join("lib"); + if !builder.config.llvm_link_shared { + // We do not need to copy LLVM files into the sysroot if it is not + // dynamically linked; it is already included into librustc_llvm + // statically. + return; + } + // On macOS for some reason the llvm-config binary behaves differently and + // and fails on missing .a files if run without --link-shared. If run with + // that option, it still fails, but because we only ship a libLLVM.dylib + // rather than libLLVM-11-rust-....dylib file. + // + // For now just don't use llvm-config here on macOS; that will fail to + // support CI-built LLVM, but until we work out the different behavior that + // is fine as it is off by default. if target.contains("apple-darwin") { + let src_libdir = builder.llvm_out(target).join("lib"); let llvm_dylib_path = src_libdir.join("libLLVM.dylib"); if llvm_dylib_path.exists() { builder.install(&llvm_dylib_path, dst_libdir, 0o644); } - return; - } - - // Usually libLLVM.so is a symlink to something like libLLVM-6.0.so. - // Since tools link to the latter rather than the former, we have to - // follow the symlink to find out what to distribute. - let llvm_dylib_path = src_libdir.join("libLLVM.so"); - if llvm_dylib_path.exists() { - let llvm_dylib_path = llvm_dylib_path.canonicalize().unwrap_or_else(|e| { - panic!("dist: Error calling canonicalize path `{}`: {}", llvm_dylib_path.display(), e); - }); - - builder.install(&llvm_dylib_path, dst_libdir, 0o644); + } else if let Ok(llvm_config) = crate::native::prebuilt_llvm_config(builder, target) { + let files = output(Command::new(llvm_config).arg("--libfiles")); + for file in files.lines() { + builder.install(Path::new(file), dst_libdir, 0o644); + } } } diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index f0224d88226..91b85f5af1d 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -541,6 +541,16 @@ fn rustc_features(&self) -> String { if self.config.llvm_enabled() { features.push_str(" llvm"); } + + // If debug logging is on, then we want the default for tracing: + // https://github.com/tokio-rs/tracing/blob/3dd5c03d907afdf2c39444a29931833335171554/tracing/src/level_filters.rs#L26 + // which is everything (including debug/trace/etc.) + // if its unset, if debug_assertions is on, then debug_logging will also be on + // as well as tracing *ignoring* this feature when debug_assertions is on + if !self.config.rust_debug_logging { + features.push_str(" max_level_info"); + } + features } @@ -611,6 +621,10 @@ fn md_doc_out(&self, target: TargetSelection) -> Interned { /// /// If no custom `llvm-config` was specified then Rust's llvm will be used. fn is_rust_llvm(&self, target: TargetSelection) -> bool { + if self.config.llvm_from_ci && target == self.config.build { + return true; + } + match self.config.target_config.get(&target) { Some(ref c) => c.llvm_config.is_none(), None => true, diff --git a/src/test/ui/proc-macro/issue-76182-leading-vert-pat.rs b/src/test/ui/proc-macro/issue-76182-leading-vert-pat.rs new file mode 100644 index 00000000000..7d31de1d22d --- /dev/null +++ b/src/test/ui/proc-macro/issue-76182-leading-vert-pat.rs @@ -0,0 +1,16 @@ +// check-pass +// aux-build:test-macros.rs +// compile-flags: -Z span-debug +// +// Regression test for issue #76182 +// Tests that we properly handle patterns with a leading vert + +#![no_std] // Don't load unnecessary hygiene information from std +extern crate std; + +extern crate test_macros; + +#[test_macros::print_attr] +fn main() { + match () { | () => () } +} diff --git a/src/test/ui/proc-macro/issue-76182-leading-vert-pat.stdout b/src/test/ui/proc-macro/issue-76182-leading-vert-pat.stdout new file mode 100644 index 00000000000..5493f9c7b60 --- /dev/null +++ b/src/test/ui/proc-macro/issue-76182-leading-vert-pat.stdout @@ -0,0 +1,62 @@ +PRINT-ATTR INPUT (DISPLAY): fn main() { match() { | () => () } } +PRINT-ATTR INPUT (DEBUG): TokenStream [ + Ident { + ident: "fn", + span: $DIR/issue-76182-leading-vert-pat.rs:14:1: 14:3 (#0), + }, + Ident { + ident: "main", + span: $DIR/issue-76182-leading-vert-pat.rs:14:4: 14:8 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/issue-76182-leading-vert-pat.rs:14:8: 14:10 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Ident { + ident: "match", + span: $DIR/issue-76182-leading-vert-pat.rs:15:5: 15:10 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/issue-76182-leading-vert-pat.rs:15:11: 15:13 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Punct { + ch: '|', + spacing: Alone, + span: $DIR/issue-76182-leading-vert-pat.rs:15:16: 15:17 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/issue-76182-leading-vert-pat.rs:15:18: 15:20 (#0), + }, + Punct { + ch: '=', + spacing: Joint, + span: $DIR/issue-76182-leading-vert-pat.rs:15:21: 15:23 (#0), + }, + Punct { + ch: '>', + spacing: Alone, + span: $DIR/issue-76182-leading-vert-pat.rs:15:21: 15:23 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/issue-76182-leading-vert-pat.rs:15:24: 15:26 (#0), + }, + ], + span: $DIR/issue-76182-leading-vert-pat.rs:15:14: 15:28 (#0), + }, + ], + span: $DIR/issue-76182-leading-vert-pat.rs:14:11: 16:2 (#0), + }, +] diff --git a/src/test/ui/proc-macro/trailing-plus.rs b/src/test/ui/proc-macro/trailing-plus.rs new file mode 100644 index 00000000000..4f61de47d85 --- /dev/null +++ b/src/test/ui/proc-macro/trailing-plus.rs @@ -0,0 +1,14 @@ +// check-pass +// aux-build:test-macros.rs +// compile-flags: -Z span-debug + +#![no_std] // Don't load unnecessary hygiene information from std +extern crate std; + +extern crate test_macros; + +#[test_macros::print_attr] +fn foo() where T: Copy + { +} + +fn main() {} diff --git a/src/test/ui/proc-macro/trailing-plus.stdout b/src/test/ui/proc-macro/trailing-plus.stdout new file mode 100644 index 00000000000..d60f400af2b --- /dev/null +++ b/src/test/ui/proc-macro/trailing-plus.stdout @@ -0,0 +1,57 @@ +PRINT-ATTR INPUT (DISPLAY): fn foo < T > () where T : Copy + { } +PRINT-ATTR INPUT (DEBUG): TokenStream [ + Ident { + ident: "fn", + span: $DIR/trailing-plus.rs:11:1: 11:3 (#0), + }, + Ident { + ident: "foo", + span: $DIR/trailing-plus.rs:11:4: 11:7 (#0), + }, + Punct { + ch: '<', + spacing: Alone, + span: $DIR/trailing-plus.rs:11:7: 11:8 (#0), + }, + Ident { + ident: "T", + span: $DIR/trailing-plus.rs:11:8: 11:9 (#0), + }, + Punct { + ch: '>', + spacing: Alone, + span: $DIR/trailing-plus.rs:11:9: 11:10 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/trailing-plus.rs:11:10: 11:12 (#0), + }, + Ident { + ident: "where", + span: $DIR/trailing-plus.rs:11:13: 11:18 (#0), + }, + Ident { + ident: "T", + span: $DIR/trailing-plus.rs:11:19: 11:20 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/trailing-plus.rs:11:20: 11:21 (#0), + }, + Ident { + ident: "Copy", + span: $DIR/trailing-plus.rs:11:22: 11:26 (#0), + }, + Punct { + ch: '+', + spacing: Alone, + span: $DIR/trailing-plus.rs:11:27: 11:28 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [], + span: $DIR/trailing-plus.rs:11:29: 12:2 (#0), + }, +]