From 67350bc8681d6df212817644cad7c748039a6238 Mon Sep 17 00:00:00 2001 From: Keegan McAllister Date: Sun, 7 Sep 2014 14:57:26 -0700 Subject: [PATCH] Don't use std:: paths in syntax extensions when compiling a #![no_std] crate Fixes #16803. Fixes #14342. Fixes half of #21827 -- slice syntax is still broken. --- src/doc/trpl/unsafe.md | 4 -- src/liballoc/lib.rs | 3 +- src/libcollections/fmt.rs | 56 +++++++++++++++ src/libcollections/lib.rs | 18 ++--- src/libcollections/macros.rs | 16 +++++ src/libcollections/ring_buf.rs | 4 +- src/libcore/iter.rs | 2 +- src/libcore/lib.rs | 24 ++++--- src/liblibc/lib.rs | 3 +- src/librand/lib.rs | 3 +- src/librustc_bitflags/lib.rs | 7 ++ src/libstd/fmt.rs | 24 +------ src/libstd/lib.rs | 14 ++-- src/libstd/macros.rs | 1 + src/libsyntax/ext/base.rs | 5 ++ src/libsyntax/ext/build.rs | 45 +++++++----- src/libsyntax/ext/deriving/bounds.rs | 8 ++- src/libsyntax/ext/deriving/clone.rs | 4 +- src/libsyntax/ext/deriving/cmp/eq.rs | 2 +- src/libsyntax/ext/deriving/cmp/ord.rs | 10 +-- src/libsyntax/ext/deriving/cmp/totaleq.rs | 2 +- src/libsyntax/ext/deriving/cmp/totalord.rs | 8 +-- src/libsyntax/ext/deriving/decodable.rs | 8 ++- src/libsyntax/ext/deriving/default.rs | 4 +- src/libsyntax/ext/deriving/encodable.rs | 8 ++- src/libsyntax/ext/deriving/hash.rs | 8 +-- src/libsyntax/ext/deriving/mod.rs | 16 +++++ src/libsyntax/ext/deriving/primitive.rs | 6 +- src/libsyntax/ext/deriving/rand.rs | 6 ++ src/libsyntax/ext/deriving/show.rs | 6 +- src/libsyntax/ext/env.rs | 4 +- src/libsyntax/ext/expand.rs | 7 +- src/libsyntax/ext/format.rs | 10 +-- src/libsyntax/std_inject.rs | 2 +- src/libunicode/lib.rs | 2 + .../derive-no-std-not-supported.rs | 37 ++++++++++ src/test/pretty/issue-4264.pp | 68 +++++++++---------- src/test/run-make/simd-ffi/simd.rs | 2 +- src/test/run-pass/derive-no-std.rs | 40 +++++++++++ src/test/run-pass/for-loop-no-std.rs | 25 +++++++ src/test/run-pass/format-no-std.rs | 36 ++++++++++ 41 files changed, 413 insertions(+), 145 deletions(-) create mode 100644 src/libcollections/fmt.rs create mode 100644 src/test/compile-fail/derive-no-std-not-supported.rs create mode 100644 src/test/run-pass/derive-no-std.rs create mode 100644 src/test/run-pass/for-loop-no-std.rs create mode 100644 src/test/run-pass/format-no-std.rs diff --git a/src/doc/trpl/unsafe.md b/src/doc/trpl/unsafe.md index 2bd86fa987f4b..3acd1eefe89d0 100644 --- a/src/doc/trpl/unsafe.md +++ b/src/doc/trpl/unsafe.md @@ -576,10 +576,6 @@ extern fn panic_fmt(args: &core::fmt::Arguments, #[lang = "eh_personality"] extern fn eh_personality() {} # #[start] fn start(argc: isize, argv: *const *const u8) -> isize { 0 } # fn main() {} -# mod std { // for-loops -# pub use core::iter; -# pub use core::option; -# } ``` Note that there is one extra lang item here which differs from the examples diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index d99a5e2cc6d4a..b3a7e3dbdebf9 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -126,7 +126,8 @@ pub fn oom() -> ! { #[doc(hidden)] pub fn fixme_14344_be_sure_to_link_to_collections() {} -#[cfg(not(test))] +// NOTE: remove after next snapshot +#[cfg(all(stage0, not(test)))] #[doc(hidden)] mod std { pub use core::fmt; diff --git a/src/libcollections/fmt.rs b/src/libcollections/fmt.rs new file mode 100644 index 0000000000000..b3f31f33a3a9e --- /dev/null +++ b/src/libcollections/fmt.rs @@ -0,0 +1,56 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Formatting support for `String`. +//! +//! See `core::fmt` and `std::fmt` for full documentation on string +//! formatting. + +#![stable(feature = "rust1", since = "1.0.0")] + +use core::fmt; + +use string; + +/// The format function takes a precompiled format string and a list of +/// arguments, to return the resulting formatted string. +/// +/// # Arguments +/// +/// * args - a structure of arguments generated via the `format_args!` macro. +/// +/// # Example +/// +/// ```rust +/// use std::fmt; +/// +/// let s = fmt::format(format_args!("Hello, {}!", "world")); +/// assert_eq!(s, "Hello, world!".to_string()); +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub fn format(args: fmt::Arguments) -> string::String { + // FIXME #21826 + use core::fmt::Writer; + let mut output = string::String::new(); + let _ = write!(&mut output, "{}", args); + output +} + +#[cfg(test)] +mod tests { + use prelude::*; + use fmt; + + #[test] + fn test_format() { + let s = fmt::format(format_args!("Hello, {}!", "world")); + assert_eq!(s.as_slice(), "Hello, world!"); + } +} diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 57c799785e82d..05d84eda13d75 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -68,6 +68,7 @@ mod bit; mod btree; pub mod dlist; pub mod enum_set; +pub mod fmt; pub mod ring_buf; pub mod slice; pub mod str; @@ -107,15 +108,16 @@ pub fn fixme_14344_be_sure_to_link_to_collections() {} #[cfg(not(test))] mod std { - pub use core::fmt; // necessary for panic!() - pub use core::option; // necessary for panic!() - pub use core::clone; // derive(Clone) - pub use core::cmp; // derive(Eq, Ord, etc.) - pub use core::marker; // derive(Copy) - pub use core::hash; // derive(Hash) + // NOTE: remove after next snapshot + #[cfg(stage0)] pub use core::clone; // derive(Clone) + #[cfg(stage0)] pub use core::cmp; // derive(Eq, Ord, etc.) + #[cfg(stage0)] pub use core::marker; // derive(Copy) + #[cfg(stage0)] pub use core::hash; // derive(Hash) + #[cfg(stage0)] pub use core::iter; + #[cfg(stage0)] pub use core::fmt; // necessary for panic!() + #[cfg(stage0)] pub use core::option; // necessary for panic!() + pub use core::ops; // RangeFull - // for-loops - pub use core::iter; } #[cfg(test)] diff --git a/src/libcollections/macros.rs b/src/libcollections/macros.rs index 15048998592a9..79c86a846f1b9 100644 --- a/src/libcollections/macros.rs +++ b/src/libcollections/macros.rs @@ -22,3 +22,19 @@ macro_rules! vec { ); ($($x:expr,)*) => (vec![$($x),*]) } + +/// Use the syntax described in `std::fmt` to create a value of type `String`. +/// See `std::fmt` for more information. +/// +/// # Example +/// +/// ``` +/// format!("test"); +/// format!("hello {}", "world!"); +/// format!("x = {}, y = {y}", 10, y = 30); +/// ``` +#[macro_export] +#[stable(feature = "rust1", since = "1.0.0")] +macro_rules! format { + ($($arg:tt)*) => ($crate::fmt::format(format_args!($($arg)*))) +} diff --git a/src/libcollections/ring_buf.rs b/src/libcollections/ring_buf.rs index 417493038404a..76849e6ade85a 100644 --- a/src/libcollections/ring_buf.rs +++ b/src/libcollections/ring_buf.rs @@ -27,8 +27,8 @@ use core::ops::{Index, IndexMut}; use core::ptr; use core::raw::Slice as RawSlice; -use std::hash::{Writer, Hash, Hasher}; -use std::cmp; +use core::hash::{Writer, Hash, Hasher}; +use core::cmp; use alloc::heap; diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index f3b42e4f0a577..5df64cfaadaaa 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -67,7 +67,7 @@ use num::{ToPrimitive, Int}; use ops::{Add, Deref, FnMut}; use option::Option; use option::Option::{Some, None}; -use std::marker::Sized; +use marker::Sized; use usize; /// An interface for dealing with "external iterators". These types of iterators diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 5e9793f270ded..4c031b3e7cc93 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -148,17 +148,25 @@ mod array; mod core { pub use panicking; pub use fmt; + #[cfg(not(stage0))] pub use clone; + #[cfg(not(stage0))] pub use cmp; + #[cfg(not(stage0))] pub use hash; + #[cfg(not(stage0))] pub use marker; + #[cfg(not(stage0))] pub use option; + #[cfg(not(stage0))] pub use iter; } #[doc(hidden)] mod std { - pub use clone; - pub use cmp; - pub use fmt; - pub use hash; - pub use marker; + // NOTE: remove after next snapshot + #[cfg(stage0)] pub use clone; + #[cfg(stage0)] pub use cmp; + #[cfg(stage0)] pub use hash; + #[cfg(stage0)] pub use marker; + #[cfg(stage0)] pub use option; + #[cfg(stage0)] pub use fmt; + #[cfg(stage0)] pub use iter; + + // range syntax pub use ops; - pub use option; - // for-loops - pub use iter; } diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs index b643b04035f2a..060e7ef403318 100644 --- a/src/liblibc/lib.rs +++ b/src/liblibc/lib.rs @@ -5729,8 +5729,9 @@ pub fn issue_14344_workaround() {} // FIXME #14344 force linkage to happen corre #[test] fn work_on_windows() { } // FIXME #10872 needed for a happy windows +// NOTE: remove after next snapshot #[doc(hidden)] -#[cfg(not(test))] +#[cfg(all(stage0, not(test)))] mod std { pub use core::marker; } diff --git a/src/librand/lib.rs b/src/librand/lib.rs index 0a64da6f137bd..777b1ed8ceb6a 100644 --- a/src/librand/lib.rs +++ b/src/librand/lib.rs @@ -496,7 +496,8 @@ pub struct Open01(pub F); /// ``` pub struct Closed01(pub F); -#[cfg(not(test))] +// NOTE: remove after next snapshot +#[cfg(all(stage0, not(test)))] mod std { pub use core::{option, fmt}; // panic!() pub use core::clone; // derive Clone diff --git a/src/librustc_bitflags/lib.rs b/src/librustc_bitflags/lib.rs index 031607728797e..0139dfbd50b47 100644 --- a/src/librustc_bitflags/lib.rs +++ b/src/librustc_bitflags/lib.rs @@ -281,6 +281,13 @@ macro_rules! bitflags { }; } +// This is a no_std crate. So the test code's invocation of #[derive] etc, via +// bitflags!, will use names from the underlying crates. +#[cfg(test)] +mod core { + pub use std::{fmt, hash, clone, cmp, marker, option}; +} + #[cfg(test)] #[allow(non_upper_case_globals)] mod tests { diff --git a/src/libstd/fmt.rs b/src/libstd/fmt.rs index 47f5d64e2607c..82823f0cb28dc 100644 --- a/src/libstd/fmt.rs +++ b/src/libstd/fmt.rs @@ -403,8 +403,6 @@ #![unstable(feature = "std_misc")] -use string; - pub use core::fmt::{Formatter, Result, Writer, rt}; pub use core::fmt::{Show, String, Octal, Binary}; pub use core::fmt::{Display, Debug}; @@ -413,24 +411,4 @@ pub use core::fmt::{LowerExp, UpperExp}; pub use core::fmt::Error; pub use core::fmt::{ArgumentV1, Arguments, write, radix, Radix, RadixFmt}; -/// The format function takes a precompiled format string and a list of -/// arguments, to return the resulting formatted string. -/// -/// # Arguments -/// -/// * args - a structure of arguments generated via the `format_args!` macro. -/// -/// # Example -/// -/// ```rust -/// use std::fmt; -/// -/// let s = fmt::format(format_args!("Hello, {}!", "world")); -/// assert_eq!(s, "Hello, world!".to_string()); -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub fn format(args: Arguments) -> string::String { - let mut output = string::String::new(); - let _ = write!(&mut output, "{}", args); - output -} +pub use core_collections::fmt::format; diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 14e779f9c4a8e..e54086159002e 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -137,7 +137,7 @@ extern crate core; #[macro_use] -#[macro_reexport(vec)] +#[macro_reexport(vec, format)] extern crate "collections" as core_collections; #[allow(deprecated)] extern crate "rand" as core_rand; @@ -285,11 +285,12 @@ mod tuple; // can be resolved within libstd. #[doc(hidden)] mod std { + // NOTE: remove after next snapshot // mods used for deriving - pub use clone; - pub use cmp; - pub use hash; - pub use default; + #[cfg(stage0)] pub use clone; + #[cfg(stage0)] pub use cmp; + #[cfg(stage0)] pub use hash; + #[cfg(stage0)] pub use default; pub use sync; // used for select!() pub use error; // used for try!() @@ -312,5 +313,6 @@ mod std { pub use boxed; // used for vec![] // for-loops - pub use iter; + // NOTE: remove after next snapshot + #[cfg(stage0)] pub use iter; } diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index e91e8241a55be..6a2aafcf8f396 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -70,6 +70,7 @@ macro_rules! panic { /// format!("hello {}", "world!"); /// format!("x = {}, y = {y}", 10, y = 30); /// ``` +#[cfg(stage0)] // NOTE: remove after snapshot #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] macro_rules! format { diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index b5f6893a8c279..778b2cabea622 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -544,6 +544,7 @@ pub struct ExtCtxt<'a> { pub cfg: ast::CrateConfig, pub backtrace: ExpnId, pub ecfg: expand::ExpansionConfig, + pub use_std: bool, pub mod_path: Vec , pub trace_mac: bool, @@ -563,6 +564,7 @@ impl<'a> ExtCtxt<'a> { backtrace: NO_EXPANSION, mod_path: Vec::new(), ecfg: ecfg, + use_std: true, trace_mac: false, exported_macros: Vec::new(), syntax_env: env, @@ -737,6 +739,9 @@ impl<'a> ExtCtxt<'a> { pub fn ident_of(&self, st: &str) -> ast::Ident { str_to_ident(st) } + pub fn ident_of_std(&self, st: &str) -> ast::Ident { + self.ident_of(if self.use_std { "std" } else { st }) + } pub fn name_of(&self, st: &str) -> ast::Name { token::intern(st) } diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 55faf692e98f3..a7d1baf08beac 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -386,7 +386,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { self.path_all(DUMMY_SP, true, vec!( - self.ident_of("std"), + self.ident_of_std("core"), self.ident_of("option"), self.ident_of("Option") ), @@ -656,7 +656,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { } fn expr_vec_ng(&self, sp: Span) -> P { self.expr_call_global(sp, - vec!(self.ident_of("std"), + vec!(self.ident_of_std("collections"), self.ident_of("vec"), self.ident_of("Vec"), self.ident_of("new")), @@ -676,7 +676,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn expr_some(&self, sp: Span, expr: P) -> P { let some = vec!( - self.ident_of("std"), + self.ident_of_std("core"), self.ident_of("option"), self.ident_of("Option"), self.ident_of("Some")); @@ -685,7 +685,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn expr_none(&self, sp: Span) -> P { let none = self.path_global(sp, vec!( - self.ident_of("std"), + self.ident_of_std("core"), self.ident_of("option"), self.ident_of("Option"), self.ident_of("None"))); @@ -712,7 +712,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { self.expr_call_global( span, vec!( - self.ident_of("std"), + self.ident_of_std("core"), self.ident_of("rt"), self.ident_of("begin_unwind")), vec!( @@ -728,7 +728,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn expr_ok(&self, sp: Span, expr: P) -> P { let ok = vec!( - self.ident_of("std"), + self.ident_of_std("core"), self.ident_of("result"), self.ident_of("Result"), self.ident_of("Ok")); @@ -737,7 +737,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn expr_err(&self, sp: Span, expr: P) -> P { let err = vec!( - self.ident_of("std"), + self.ident_of_std("core"), self.ident_of("result"), self.ident_of("Result"), self.ident_of("Err")); @@ -745,10 +745,20 @@ impl<'a> AstBuilder for ExtCtxt<'a> { } fn expr_try(&self, sp: Span, head: P) -> P { - let ok = self.ident_of("Ok"); - let ok_path = self.path_ident(sp, ok); - let err = self.ident_of("Err"); - let err_path = self.path_ident(sp, err); + let ok = vec![ + self.ident_of_std("core"), + self.ident_of("result"), + self.ident_of("Result"), + self.ident_of("Ok") + ]; + let ok_path = self.path_global(sp, ok); + let err = vec![ + self.ident_of_std("core"), + self.ident_of("result"), + self.ident_of("Result"), + self.ident_of("Err") + ]; + let err_path = self.path_global(sp, err); let binding_variable = self.ident_of("__try_var"); let binding_pat = self.pat_ident(sp, binding_variable); @@ -758,8 +768,9 @@ impl<'a> AstBuilder for ExtCtxt<'a> { let ok_pat = self.pat_enum(sp, ok_path, vec!(binding_pat.clone())); // Err(__try_var) (pattern and expression resp.) - let err_pat = self.pat_enum(sp, err_path, vec!(binding_pat)); - let err_inner_expr = self.expr_call_ident(sp, err, vec!(binding_expr.clone())); + let err_pat = self.pat_enum(sp, err_path.clone(), vec!(binding_pat)); + let err_inner_expr = self.expr_call(sp, self.expr_path(err_path), + vec!(binding_expr.clone())); // return Err(__try_var) let err_expr = self.expr(sp, ast::ExprRet(Some(err_inner_expr))); @@ -808,7 +819,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn pat_some(&self, span: Span, pat: P) -> P { let some = vec!( - self.ident_of("std"), + self.ident_of_std("core"), self.ident_of("option"), self.ident_of("Option"), self.ident_of("Some")); @@ -818,7 +829,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn pat_none(&self, span: Span) -> P { let some = vec!( - self.ident_of("std"), + self.ident_of_std("core"), self.ident_of("option"), self.ident_of("Option"), self.ident_of("None")); @@ -828,7 +839,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn pat_ok(&self, span: Span, pat: P) -> P { let some = vec!( - self.ident_of("std"), + self.ident_of_std("core"), self.ident_of("result"), self.ident_of("Result"), self.ident_of("Ok")); @@ -838,7 +849,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn pat_err(&self, span: Span, pat: P) -> P { let some = vec!( - self.ident_of("std"), + self.ident_of_std("core"), self.ident_of("result"), self.ident_of("Result"), self.ident_of("Err")); diff --git a/src/libsyntax/ext/deriving/bounds.rs b/src/libsyntax/ext/deriving/bounds.rs index 1c82ca5d2add7..879718a6399f5 100644 --- a/src/libsyntax/ext/deriving/bounds.rs +++ b/src/libsyntax/ext/deriving/bounds.rs @@ -45,10 +45,16 @@ pub fn expand_deriving_bound(cx: &mut ExtCtxt, } }; + let path = Path::new(vec![ + if cx.use_std { "std" } else { "core" }, + "marker", + name + ]); + let trait_def = TraitDef { span: span, attributes: Vec::new(), - path: Path::new(vec!("std", "marker", name)), + path: path, additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), methods: Vec::new(), diff --git a/src/libsyntax/ext/deriving/clone.rs b/src/libsyntax/ext/deriving/clone.rs index 847af6427ef35..9f009ad4d7869 100644 --- a/src/libsyntax/ext/deriving/clone.rs +++ b/src/libsyntax/ext/deriving/clone.rs @@ -29,7 +29,7 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt, let trait_def = TraitDef { span: span, attributes: Vec::new(), - path: path!(std::clone::Clone), + path: path_std!(cx, core::clone::Clone), additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), methods: vec!( @@ -58,7 +58,7 @@ fn cs_clone( let ctor_path; let all_fields; let fn_path = vec![ - cx.ident_of("std"), + cx.ident_of_std("core"), cx.ident_of("clone"), cx.ident_of("Clone"), cx.ident_of("clone"), diff --git a/src/libsyntax/ext/deriving/cmp/eq.rs b/src/libsyntax/ext/deriving/cmp/eq.rs index 65c164fc9a159..91212a8695896 100644 --- a/src/libsyntax/ext/deriving/cmp/eq.rs +++ b/src/libsyntax/ext/deriving/cmp/eq.rs @@ -82,7 +82,7 @@ pub fn expand_deriving_eq(cx: &mut ExtCtxt, let trait_def = TraitDef { span: span, attributes: Vec::new(), - path: path!(std::cmp::PartialEq), + path: path_std!(cx, core::cmp::PartialEq), additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), methods: vec!( diff --git a/src/libsyntax/ext/deriving/cmp/ord.rs b/src/libsyntax/ext/deriving/cmp/ord.rs index 8a706e5c46d64..b109850a6bd23 100644 --- a/src/libsyntax/ext/deriving/cmp/ord.rs +++ b/src/libsyntax/ext/deriving/cmp/ord.rs @@ -45,8 +45,8 @@ pub fn expand_deriving_ord(cx: &mut ExtCtxt, } } } - let ordering_ty = Literal(path!(std::cmp::Ordering)); - let ret_ty = Literal(Path::new_(pathvec!(std::option::Option), + let ordering_ty = Literal(path_std!(cx, core::cmp::Ordering)); + let ret_ty = Literal(Path::new_(pathvec_std!(cx, core::option::Option), None, vec![box ordering_ty], true)); @@ -69,7 +69,7 @@ pub fn expand_deriving_ord(cx: &mut ExtCtxt, let trait_def = TraitDef { span: span, attributes: vec![], - path: path!(std::cmp::PartialOrd), + path: path_std!(cx, core::cmp::PartialOrd), additional_bounds: vec![], generics: LifetimeBounds::empty(), methods: vec![ @@ -107,7 +107,7 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { let test_id = cx.ident_of("__test"); let ordering = cx.path_global(span, - vec!(cx.ident_of("std"), + vec!(cx.ident_of_std("core"), cx.ident_of("cmp"), cx.ident_of("Ordering"), cx.ident_of("Equal"))); @@ -115,7 +115,7 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, let equals_expr = cx.expr_some(span, ordering); let partial_cmp_path = vec![ - cx.ident_of("std"), + cx.ident_of_std("core"), cx.ident_of("cmp"), cx.ident_of("PartialOrd"), cx.ident_of("partial_cmp"), diff --git a/src/libsyntax/ext/deriving/cmp/totaleq.rs b/src/libsyntax/ext/deriving/cmp/totaleq.rs index 9efae379e1f0f..31a754a1254bb 100644 --- a/src/libsyntax/ext/deriving/cmp/totaleq.rs +++ b/src/libsyntax/ext/deriving/cmp/totaleq.rs @@ -46,7 +46,7 @@ pub fn expand_deriving_totaleq(cx: &mut ExtCtxt, let trait_def = TraitDef { span: span, attributes: Vec::new(), - path: path!(std::cmp::Eq), + path: path_std!(cx, core::cmp::Eq), additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), methods: vec!( diff --git a/src/libsyntax/ext/deriving/cmp/totalord.rs b/src/libsyntax/ext/deriving/cmp/totalord.rs index 7a4b717e817fc..2f6f99bc1ee46 100644 --- a/src/libsyntax/ext/deriving/cmp/totalord.rs +++ b/src/libsyntax/ext/deriving/cmp/totalord.rs @@ -30,7 +30,7 @@ pub fn expand_deriving_totalord(cx: &mut ExtCtxt, let trait_def = TraitDef { span: span, attributes: Vec::new(), - path: path!(std::cmp::Ord), + path: path_std!(cx, core::cmp::Ord), additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), methods: vec!( @@ -39,7 +39,7 @@ pub fn expand_deriving_totalord(cx: &mut ExtCtxt, generics: LifetimeBounds::empty(), explicit_self: borrowed_explicit_self(), args: vec!(borrowed_self()), - ret_ty: Literal(path!(std::cmp::Ordering)), + ret_ty: Literal(path_std!(cx, core::cmp::Ordering)), attributes: attrs, combine_substructure: combine_substructure(box |a, b, c| { cs_cmp(a, b, c) @@ -65,13 +65,13 @@ pub fn cs_cmp(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { let test_id = cx.ident_of("__test"); let equals_path = cx.path_global(span, - vec!(cx.ident_of("std"), + vec!(cx.ident_of_std("core"), cx.ident_of("cmp"), cx.ident_of("Ordering"), cx.ident_of("Equal"))); let cmp_path = vec![ - cx.ident_of("std"), + cx.ident_of_std("core"), cx.ident_of("cmp"), cx.ident_of("Ord"), cx.ident_of("cmp"), diff --git a/src/libsyntax/ext/deriving/decodable.rs b/src/libsyntax/ext/deriving/decodable.rs index e7ef2ff060641..f003a3453e15e 100644 --- a/src/libsyntax/ext/deriving/decodable.rs +++ b/src/libsyntax/ext/deriving/decodable.rs @@ -49,6 +49,12 @@ fn expand_deriving_decodable_imp(cx: &mut ExtCtxt, krate: &'static str) where F: FnOnce(P), { + if !cx.use_std { + // FIXME(#21880): lift this requirement. + cx.span_err(span, "this trait cannot be derived with #![no_std]"); + return; + } + let trait_def = TraitDef { span: span, attributes: Vec::new(), @@ -68,7 +74,7 @@ fn expand_deriving_decodable_imp(cx: &mut ExtCtxt, args: vec!(Ptr(box Literal(Path::new_local("__D")), Borrowed(None, MutMutable))), ret_ty: Literal(Path::new_( - pathvec!(std::result::Result), + pathvec_std!(cx, core::result::Result), None, vec!(box Self, box Literal(Path::new_( vec!["__D", "Error"], None, vec![], false diff --git a/src/libsyntax/ext/deriving/default.rs b/src/libsyntax/ext/deriving/default.rs index 8f210779d3d13..9b76f4b1658f0 100644 --- a/src/libsyntax/ext/deriving/default.rs +++ b/src/libsyntax/ext/deriving/default.rs @@ -29,7 +29,7 @@ pub fn expand_deriving_default(cx: &mut ExtCtxt, let trait_def = TraitDef { span: span, attributes: Vec::new(), - path: path!(std::default::Default), + path: path_std!(cx, core::default::Default), additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), methods: vec!( @@ -52,7 +52,7 @@ pub fn expand_deriving_default(cx: &mut ExtCtxt, fn default_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P { let default_ident = vec!( - cx.ident_of("std"), + cx.ident_of_std("core"), cx.ident_of("default"), cx.ident_of("Default"), cx.ident_of("default") diff --git a/src/libsyntax/ext/deriving/encodable.rs b/src/libsyntax/ext/deriving/encodable.rs index c3d42b6a4f7a7..dd6094705995e 100644 --- a/src/libsyntax/ext/deriving/encodable.rs +++ b/src/libsyntax/ext/deriving/encodable.rs @@ -125,6 +125,12 @@ fn expand_deriving_encodable_imp(cx: &mut ExtCtxt, krate: &'static str) where F: FnOnce(P), { + if !cx.use_std { + // FIXME(#21880): lift this requirement. + cx.span_err(span, "this trait cannot be derived with #![no_std]"); + return; + } + let trait_def = TraitDef { span: span, attributes: Vec::new(), @@ -144,7 +150,7 @@ fn expand_deriving_encodable_imp(cx: &mut ExtCtxt, args: vec!(Ptr(box Literal(Path::new_local("__S")), Borrowed(None, MutMutable))), ret_ty: Literal(Path::new_( - pathvec!(std::result::Result), + pathvec_std!(cx, core::result::Result), None, vec!(box Tuple(Vec::new()), box Literal(Path::new_( vec!["__S", "Error"], None, vec![], false diff --git a/src/libsyntax/ext/deriving/hash.rs b/src/libsyntax/ext/deriving/hash.rs index 2482ea4b7d40d..5aa9f9a0c3e76 100644 --- a/src/libsyntax/ext/deriving/hash.rs +++ b/src/libsyntax/ext/deriving/hash.rs @@ -25,13 +25,13 @@ pub fn expand_deriving_hash(cx: &mut ExtCtxt, F: FnOnce(P), { - let path = Path::new_(pathvec!(std::hash::Hash), None, + let path = Path::new_(pathvec_std!(cx, core::hash::Hash), None, vec!(box Literal(Path::new_local("__S"))), true); let generics = LifetimeBounds { lifetimes: Vec::new(), bounds: vec!(("__S", - vec!(path!(std::hash::Writer), - path!(std::hash::Hasher)))), + vec!(path_std!(cx, core::hash::Writer), + path_std!(cx, core::hash::Hasher)))), }; let args = Path::new_local("__S"); let inline = cx.meta_word(span, InternedString::new("inline")); @@ -69,7 +69,7 @@ fn hash_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) let call_hash = |span, thing_expr| { let hash_path = { let strs = vec![ - cx.ident_of("std"), + cx.ident_of_std("core"), cx.ident_of("hash"), cx.ident_of("Hash"), cx.ident_of("hash"), diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs index 657ecc63a38dd..9c3fa58ad0960 100644 --- a/src/libsyntax/ext/deriving/mod.rs +++ b/src/libsyntax/ext/deriving/mod.rs @@ -30,6 +30,22 @@ macro_rules! path { ) } +macro_rules! pathvec_std { + ($cx:expr, $first:ident :: $($rest:ident)::+) => ( + if $cx.use_std { + pathvec!(std :: $($rest)::+) + } else { + pathvec!($first :: $($rest)::+) + } + ) +} + +macro_rules! path_std { + ($($x:tt)*) => ( + ::ext::deriving::generic::ty::Path::new( pathvec_std!( $($x)* ) ) + ) +} + pub mod bounds; pub mod clone; pub mod encodable; diff --git a/src/libsyntax/ext/deriving/primitive.rs b/src/libsyntax/ext/deriving/primitive.rs index 3b5d483017f94..bf742263c6d87 100644 --- a/src/libsyntax/ext/deriving/primitive.rs +++ b/src/libsyntax/ext/deriving/primitive.rs @@ -30,7 +30,7 @@ pub fn expand_deriving_from_primitive(cx: &mut ExtCtxt, let trait_def = TraitDef { span: span, attributes: Vec::new(), - path: path!(std::num::FromPrimitive), + path: path_std!(cx, core::num::FromPrimitive), additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), methods: vec!( @@ -39,7 +39,7 @@ pub fn expand_deriving_from_primitive(cx: &mut ExtCtxt, generics: LifetimeBounds::empty(), explicit_self: None, args: vec!(Literal(path!(i64))), - ret_ty: Literal(Path::new_(pathvec!(std::option::Option), + ret_ty: Literal(Path::new_(pathvec_std!(cx, core::option::Option), None, vec!(box Self), true)), @@ -54,7 +54,7 @@ pub fn expand_deriving_from_primitive(cx: &mut ExtCtxt, generics: LifetimeBounds::empty(), explicit_self: None, args: vec!(Literal(path!(u64))), - ret_ty: Literal(Path::new_(pathvec!(std::option::Option), + ret_ty: Literal(Path::new_(pathvec_std!(cx, core::option::Option), None, vec!(box Self), true)), diff --git a/src/libsyntax/ext/deriving/rand.rs b/src/libsyntax/ext/deriving/rand.rs index 84486f770fa17..4c3678d9572da 100644 --- a/src/libsyntax/ext/deriving/rand.rs +++ b/src/libsyntax/ext/deriving/rand.rs @@ -28,6 +28,12 @@ pub fn expand_deriving_rand(cx: &mut ExtCtxt, "`#[derive(Rand)]` is deprecated in favour of `#[derive_Rand]` from \ `rand_macros` on crates.io"); + if !cx.use_std { + // FIXME(#21880): lift this requirement. + cx.span_err(span, "this trait cannot be derived with #![no_std]"); + return; + } + let trait_def = TraitDef { span: span, attributes: Vec::new(), diff --git a/src/libsyntax/ext/deriving/show.rs b/src/libsyntax/ext/deriving/show.rs index d12035193f839..3f5947672e022 100644 --- a/src/libsyntax/ext/deriving/show.rs +++ b/src/libsyntax/ext/deriving/show.rs @@ -29,13 +29,13 @@ pub fn expand_deriving_show(cx: &mut ExtCtxt, F: FnOnce(P), { // &mut ::std::fmt::Formatter - let fmtr = Ptr(box Literal(path!(std::fmt::Formatter)), + let fmtr = Ptr(box Literal(path_std!(cx, core::fmt::Formatter)), Borrowed(None, ast::MutMutable)); let trait_def = TraitDef { span: span, attributes: Vec::new(), - path: path!(std::fmt::Debug), + path: path_std!(cx, core::fmt::Debug), additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), methods: vec![ @@ -44,7 +44,7 @@ pub fn expand_deriving_show(cx: &mut ExtCtxt, generics: LifetimeBounds::empty(), explicit_self: borrowed_explicit_self(), args: vec!(fmtr), - ret_ty: Literal(path!(std::fmt::Result)), + ret_ty: Literal(path_std!(cx, core::fmt::Result)), attributes: Vec::new(), combine_substructure: combine_substructure(box |a, b, c| { show_substructure(a, b, c) diff --git a/src/libsyntax/ext/env.rs b/src/libsyntax/ext/env.rs index 417506cf3aadb..ef9d379987932 100644 --- a/src/libsyntax/ext/env.rs +++ b/src/libsyntax/ext/env.rs @@ -34,7 +34,7 @@ pub fn expand_option_env<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenT Err(..) => { cx.expr_path(cx.path_all(sp, true, - vec!(cx.ident_of("std"), + vec!(cx.ident_of_std("core"), cx.ident_of("option"), cx.ident_of("Option"), cx.ident_of("None")), @@ -50,7 +50,7 @@ pub fn expand_option_env<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenT } Ok(s) => { cx.expr_call_global(sp, - vec!(cx.ident_of("std"), + vec!(cx.ident_of_std("core"), cx.ident_of("option"), cx.ident_of("Option"), cx.ident_of("Some")), diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 33712dae900b8..95e015fee6d3c 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -31,6 +31,7 @@ use ptr::P; use util::small_vector::SmallVector; use visit; use visit::Visitor; +use std_inject; pub fn expand_type(t: P, fld: &mut MacroExpander, @@ -275,7 +276,7 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { let match_expr = { let next_path = { let strs = vec![ - fld.cx.ident_of("std"), + fld.cx.ident_of_std("core"), fld.cx.ident_of("iter"), fld.cx.ident_of("Iterator"), fld.cx.ident_of("next"), @@ -308,7 +309,7 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { let into_iter_expr = { let into_iter_path = { let strs = vec![ - fld.cx.ident_of("std"), + fld.cx.ident_of_std("core"), fld.cx.ident_of("iter"), fld.cx.ident_of("IntoIterator"), fld.cx.ident_of("into_iter"), @@ -1417,6 +1418,8 @@ pub fn expand_crate(parse_sess: &parse::ParseSess, user_exts: Vec, c: Crate) -> Crate { let mut cx = ExtCtxt::new(parse_sess, c.config.clone(), cfg); + cx.use_std = std_inject::use_std(&c); + let mut expander = MacroExpander::new(&mut cx); for def in imported_macros { diff --git a/src/libsyntax/ext/format.rs b/src/libsyntax/ext/format.rs index 96055e3635a60..170a455a91326 100644 --- a/src/libsyntax/ext/format.rs +++ b/src/libsyntax/ext/format.rs @@ -302,7 +302,7 @@ impl<'a, 'b> Context<'a, 'b> { } fn rtpath(ecx: &ExtCtxt, s: &str) -> Vec { - vec![ecx.ident_of("std"), ecx.ident_of("fmt"), ecx.ident_of("rt"), + vec![ecx.ident_of_std("core"), ecx.ident_of("fmt"), ecx.ident_of("rt"), ecx.ident_of("v1"), ecx.ident_of(s)] } @@ -576,7 +576,7 @@ impl<'a, 'b> Context<'a, 'b> { }; self.ecx.expr_call_global(self.fmtsp, vec!( - self.ecx.ident_of("std"), + self.ecx.ident_of_std("core"), self.ecx.ident_of("fmt"), self.ecx.ident_of("Arguments"), self.ecx.ident_of(fn_name)), fn_args) @@ -607,7 +607,7 @@ impl<'a, 'b> Context<'a, 'b> { } Unsigned => { return ecx.expr_call_global(sp, vec![ - ecx.ident_of("std"), + ecx.ident_of_std("core"), ecx.ident_of("fmt"), ecx.ident_of("ArgumentV1"), ecx.ident_of("from_uint")], vec![arg]) @@ -615,12 +615,12 @@ impl<'a, 'b> Context<'a, 'b> { }; let format_fn = ecx.path_global(sp, vec![ - ecx.ident_of("std"), + ecx.ident_of_std("core"), ecx.ident_of("fmt"), ecx.ident_of(trait_), ecx.ident_of("fmt")]); ecx.expr_call_global(sp, vec![ - ecx.ident_of("std"), + ecx.ident_of_std("core"), ecx.ident_of("fmt"), ecx.ident_of("ArgumentV1"), ecx.ident_of("new")], vec![arg, ecx.expr_path(format_fn)]) diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index d75fbcf199dbe..630b08f005629 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -37,7 +37,7 @@ pub fn maybe_inject_prelude(krate: ast::Crate) -> ast::Crate { } } -fn use_std(krate: &ast::Crate) -> bool { +pub fn use_std(krate: &ast::Crate) -> bool { !attr::contains_name(&krate.attrs[], "no_std") } diff --git a/src/libunicode/lib.rs b/src/libunicode/lib.rs index 822dde7eb2c61..60fa8f0db115c 100644 --- a/src/libunicode/lib.rs +++ b/src/libunicode/lib.rs @@ -78,7 +78,9 @@ pub mod str { pub use u_str::{utf16_items, Utf16Encoder}; } +// NOTE: remove after next snapshot // this lets us use #[derive(..)] +#[cfg(stage0)] mod std { pub use core::clone; pub use core::cmp; diff --git a/src/test/compile-fail/derive-no-std-not-supported.rs b/src/test/compile-fail/derive-no-std-not-supported.rs new file mode 100644 index 0000000000000..7dee78e2672f3 --- /dev/null +++ b/src/test/compile-fail/derive-no-std-not-supported.rs @@ -0,0 +1,37 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![no_std] + +extern crate core; +extern crate rand; +extern crate "serialize" as rustc_serialize; + +#[derive(Rand)] //~ ERROR this trait cannot be derived +//~^ WARNING `#[derive(Rand)]` is deprecated +struct Foo { + x: u32, +} + +#[derive(RustcEncodable)] //~ ERROR this trait cannot be derived +struct Bar { + x: u32, +} + +#[derive(RustcDecodable)] //~ ERROR this trait cannot be derived +struct Baz { + x: u32, +} + +fn main() { + Foo { x: 0 }; + Bar { x: 0 }; + Baz { x: 0 }; +} diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index cc8337027b092..a10e3449039d4 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -41,41 +41,41 @@ ((::std::fmt::format as - fn(core::fmt::Arguments<'_>) -> collections::string::String {std::fmt::format})(((::std::fmt::Arguments::new_v1 - as - fn(&[&str], &[core::fmt::ArgumentV1<'_>]) -> core::fmt::Arguments<'_> {core::fmt::Arguments<'a>::new_v1})(({ - static __STATIC_FMTSTR: - &'static [&'static str] - = - (&([("test" + fn(core::fmt::Arguments<'_>) -> collections::string::String {collections::fmt::format})(((::std::fmt::Arguments::new_v1 + as + fn(&[&str], &[core::fmt::ArgumentV1<'_>]) -> core::fmt::Arguments<'_> {core::fmt::Arguments<'a>::new_v1})(({ + static __STATIC_FMTSTR: + &'static [&'static str] + = + (&([("test" + as + &'static str)] + as + [&'static str; 1]) + as + &'static [&'static str; 1]); + (__STATIC_FMTSTR as - &'static str)] - as - [&'static str; 1]) - as - &'static [&'static str; 1]); - (__STATIC_FMTSTR - as - &'static [&'static str]) - } - as - &[&str]), - (&(match (() - as - ()) - { - () - => - ([] - as - [core::fmt::ArgumentV1<'_>; 0]), - } - as - [core::fmt::ArgumentV1<'_>; 0]) - as - &[core::fmt::ArgumentV1<'_>; 0])) - as - core::fmt::Arguments<'_>)) + &'static [&'static str]) + } + as + &[&str]), + (&(match (() + as + ()) + { + () + => + ([] + as + [core::fmt::ArgumentV1<'_>; 0]), + } + as + [core::fmt::ArgumentV1<'_>; 0]) + as + &[core::fmt::ArgumentV1<'_>; 0])) + as + core::fmt::Arguments<'_>)) as collections::string::String); } pub type Foo = [i32; (3us as usize)]; diff --git a/src/test/run-make/simd-ffi/simd.rs b/src/test/run-make/simd-ffi/simd.rs index 76079ddb8bd91..0195076fde470 100755 --- a/src/test/run-make/simd-ffi/simd.rs +++ b/src/test/run-make/simd-ffi/simd.rs @@ -74,7 +74,7 @@ trait Sized {} #[lang = "copy"] trait Copy {} -mod std { +mod core { pub mod marker { pub use Copy; } diff --git a/src/test/run-pass/derive-no-std.rs b/src/test/run-pass/derive-no-std.rs new file mode 100644 index 0000000000000..c9bbb204ab7f9 --- /dev/null +++ b/src/test/run-pass/derive-no-std.rs @@ -0,0 +1,40 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![no_std] + +extern crate core; +extern crate rand; +extern crate "serialize" as rustc_serialize; +extern crate collections; + +// Issue #16803 + +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, + Debug, Default, Copy)] +struct Foo { + x: u32, +} + +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, + Debug, Copy)] +enum Bar { + Qux, + Quux(u32), +} + +#[derive(FromPrimitive)] +enum Baz { A=0, B=5, } + +fn main() { + Foo { x: 0 }; + Bar::Quux(3); + Baz::A; +} diff --git a/src/test/run-pass/for-loop-no-std.rs b/src/test/run-pass/for-loop-no-std.rs new file mode 100644 index 0000000000000..5911e95349f32 --- /dev/null +++ b/src/test/run-pass/for-loop-no-std.rs @@ -0,0 +1,25 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![no_std] +#![feature(lang_items, start)] + +extern crate "std" as other; + +#[macro_use] extern crate core; +#[macro_use] extern crate collections; + +use core::slice::SliceExt; + +#[start] +fn start(_argc: int, _argv: *const *const u8) -> int { + for _ in [1,2,3].iter() { } + 0 +} diff --git a/src/test/run-pass/format-no-std.rs b/src/test/run-pass/format-no-std.rs new file mode 100644 index 0000000000000..43f7b6f40332f --- /dev/null +++ b/src/test/run-pass/format-no-std.rs @@ -0,0 +1,36 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![no_std] +#![feature(lang_items, start)] + +extern crate "std" as other; + +#[macro_use] extern crate core; +#[macro_use] extern crate collections; + +use collections::string::ToString; + +#[start] +fn start(_argc: int, _argv: *const *const u8) -> int { + let s = format!("{}", 1i); + assert_eq!(s, "1".to_string()); + + let s = format!("test"); + assert_eq!(s, "test".to_string()); + + let s = format!("{test}", test=3i); + assert_eq!(s, "3".to_string()); + + let s = format!("hello {}", "world"); + assert_eq!(s, "hello world".to_string()); + + 0 +}