提交 f342bea9 编写于 作者: B bors

Auto merge of #98963 - GuillaumeGomez:rollup-n030us5, r=GuillaumeGomez

Rollup of 6 pull requests

Successful merges:

 - #95503 (bootstrap: Allow building individual crates)
 - #96814 (Fix repr(align) enum handling)
 - #98256 (Fix whitespace handling after where clause)
 - #98880 (Proper macOS libLLVM symlink when cross compiling)
 - #98944 (Edit `rustc_mir_dataflow::framework::lattice::FlatSet` docs)
 - #98951 (Update books)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
......@@ -1418,9 +1418,9 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<Layout<'tcx>, LayoutError<'
if layout_variants.iter().all(|v| v.abi.is_uninhabited()) {
abi = Abi::Uninhabited;
} else if tag.size(dl) == size || variants.iter().all(|layout| layout.is_empty()) {
// Without latter check aligned enums with custom discriminant values
// Would result in ICE see the issue #92464 for more info
} else if tag.size(dl) == size {
// Make sure we only use scalar layout when the enum is entirely its
// own tag (i.e. it has no padding nor any non-ZST variant fields).
abi = Abi::Scalar(tag);
} else {
// Try to use a ScalarPair for all tagged enums.
......
......@@ -199,14 +199,16 @@ fn meet(&mut self, other: &Self) -> bool {
}
/// Extends a type `T` with top and bottom elements to make it a partially ordered set in which no
/// value of `T` is comparable with any other. A flat set has the following [Hasse diagram]:
/// value of `T` is comparable with any other.
///
/// A flat set has the following [Hasse diagram]:
///
/// ```text
/// top
/// / / \ \
/// top
/// / ... / / \ \ ... \
/// all possible values of `T`
/// \ \ / /
/// bottom
/// \ ... \ \ / / ... /
/// bottom
/// ```
///
/// [Hasse diagram]: https://en.wikipedia.org/wiki/Hasse_diagram
......
......@@ -13,7 +13,6 @@
use std::time::{Duration, Instant};
use crate::cache::{Cache, Interned, INTERNER};
use crate::compile;
use crate::config::{SplitDebuginfo, TargetSelection};
use crate::dist;
use crate::doc;
......@@ -26,6 +25,7 @@
use crate::util::{self, add_dylib_path, add_link_lib_path, exe, libdir, output, t};
use crate::EXTRA_CHECK_CFGS;
use crate::{check, Config};
use crate::{compile, Crate};
use crate::{Build, CLang, DocTests, GitRepo, Mode};
pub use crate::Compiler;
......@@ -304,9 +304,7 @@ fn run(v: &[StepDescription], builder: &Builder<'_>, paths: &[PathBuf]) {
if paths.is_empty() || builder.config.include_default_paths {
for (desc, should_run) in v.iter().zip(&should_runs) {
if desc.default && should_run.is_really_default() {
for pathset in &should_run.paths {
desc.maybe_run(builder, vec![pathset.clone()]);
}
desc.maybe_run(builder, should_run.paths.iter().cloned().collect());
}
}
}
......@@ -424,8 +422,16 @@ pub fn all_krates(mut self, name: &str) -> Self {
/// any of its (local) dependencies.
///
/// `make_run` will be called a single time with all matching command-line paths.
pub fn krate(mut self, name: &str) -> Self {
for krate in self.builder.in_tree_crates(name, None) {
pub fn crate_or_deps(self, name: &str) -> Self {
let crates = self.builder.in_tree_crates(name, None);
self.crates(crates)
}
/// Indicates it should run if the command-line selects any of the given crates.
///
/// `make_run` will be called a single time with all matching command-line paths.
pub(crate) fn crates(mut self, crates: Vec<&Crate>) -> Self {
for krate in crates {
let path = krate.local_path(self.builder);
self.paths.insert(PathSet::one(path, self.kind));
}
......@@ -581,6 +587,7 @@ fn get_step_descriptions(kind: Kind) -> Vec<StepDescription> {
match kind {
Kind::Build => describe!(
compile::Std,
compile::Rustc,
compile::Assemble,
compile::CodegenBackend,
compile::StartupObjects,
......
......@@ -57,6 +57,24 @@ fn run_build(paths: &[PathBuf], config: Config) -> Cache {
);
}
macro_rules! std {
($host:ident => $target:ident, stage = $stage:literal) => {
compile::Std::new(
Compiler { host: TargetSelection::from_user(stringify!($host)), stage: $stage },
TargetSelection::from_user(stringify!($target)),
)
};
}
macro_rules! rustc {
($host:ident => $target:ident, stage = $stage:literal) => {
compile::Rustc::new(
Compiler { host: TargetSelection::from_user(stringify!($host)), stage: $stage },
TargetSelection::from_user(stringify!($target)),
)
};
}
#[test]
fn test_valid() {
// make sure multi suite paths are accepted
......@@ -117,6 +135,17 @@ fn test_exclude_kind() {
assert!(run_build(&[path], config).contains::<tool::CargoTest>());
}
/// Ensure that if someone passes both a single crate and `library`, all library crates get built.
#[test]
fn alias_and_path_for_library() {
let mut cache =
run_build(&["library".into(), "core".into()], configure("build", &["A"], &["A"]));
assert_eq!(
first(cache.all::<compile::Std>()),
&[std!(A => A, stage = 0), std!(A => A, stage = 1)]
);
}
mod defaults {
use super::{configure, first, run_build};
use crate::builder::*;
......@@ -130,10 +159,7 @@ fn build_default() {
let a = TargetSelection::from_user("A");
assert_eq!(
first(cache.all::<compile::Std>()),
&[
compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
]
&[std!(A => A, stage = 0), std!(A => A, stage = 1),]
);
assert!(!cache.all::<compile::Assemble>().is_empty());
// Make sure rustdoc is only built once.
......@@ -143,10 +169,7 @@ fn build_default() {
// - this is the compiler it's _linked_ to, not built with.
&[tool::Rustdoc { compiler: Compiler { host: a, stage: 1 } }],
);
assert_eq!(
first(cache.all::<compile::Rustc>()),
&[compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a },]
);
assert_eq!(first(cache.all::<compile::Rustc>()), &[rustc!(A => A, stage = 0)],);
}
#[test]
......@@ -155,10 +178,7 @@ fn build_stage_0() {
let mut cache = run_build(&[], config);
let a = TargetSelection::from_user("A");
assert_eq!(
first(cache.all::<compile::Std>()),
&[compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },]
);
assert_eq!(first(cache.all::<compile::Std>()), &[std!(A => A, stage = 0)]);
assert!(!cache.all::<compile::Assemble>().is_empty());
assert_eq!(
first(cache.all::<tool::Rustdoc>()),
......@@ -185,10 +205,10 @@ fn build_cross_compile() {
assert_eq!(
first(cache.all::<compile::Std>()),
&[
compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
compile::Std { compiler: Compiler { host: a, stage: 0 }, target: b },
compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
std!(A => A, stage = 0),
std!(A => A, stage = 1),
std!(A => B, stage = 0),
std!(A => B, stage = 1),
]
);
assert_eq!(
......@@ -208,10 +228,7 @@ fn build_cross_compile() {
);
assert_eq!(
first(cache.all::<compile::Rustc>()),
&[
compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a },
compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: b },
]
&[rustc!(A => A, stage = 0), rustc!(A => B, stage = 0),]
);
}
......@@ -334,11 +351,11 @@ fn dist_with_hosts() {
assert_eq!(
first(cache.all::<compile::Std>()),
&[
compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
compile::Std { compiler: Compiler { host: a, stage: 2 }, target: a },
compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b },
std!(A => A, stage = 0),
std!(A => A, stage = 1),
std!(A => A, stage = 2),
std!(A => B, stage = 1),
std!(A => B, stage = 2),
],
);
assert_eq!(first(cache.all::<dist::Src>()), &[dist::Src]);
......@@ -346,7 +363,6 @@ fn dist_with_hosts() {
#[test]
fn dist_only_cross_host() {
let a = TargetSelection::from_user("A");
let b = TargetSelection::from_user("B");
let mut config = configure(&["A", "B"], &["A", "B"]);
config.docs = false;
......@@ -360,10 +376,7 @@ fn dist_only_cross_host() {
);
assert_eq!(
first(cache.all::<compile::Rustc>()),
&[
compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a },
compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: b },
]
&[rustc!(A => A, stage = 0), rustc!(A => B, stage = 1),]
);
}
......@@ -450,11 +463,11 @@ fn dist_with_same_targets_and_hosts() {
assert_eq!(
first(cache.all::<compile::Std>()),
&[
compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
compile::Std { compiler: Compiler { host: a, stage: 2 }, target: a },
compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b },
std!(A => A, stage = 0),
std!(A => A, stage = 1),
std!(A => A, stage = 2),
std!(A => B, stage = 1),
std!(A => B, stage = 2),
]
);
assert_eq!(
......@@ -474,33 +487,29 @@ fn build_all() {
let mut builder = Builder::new(&build);
builder.run_step_descriptions(
&Builder::get_step_descriptions(Kind::Build),
&["compiler/rustc".into(), "library/std".into()],
&["compiler/rustc".into(), "library".into()],
);
let a = TargetSelection::from_user("A");
let b = TargetSelection::from_user("B");
let c = TargetSelection::from_user("C");
assert_eq!(
first(builder.cache.all::<compile::Std>()),
&[
compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
compile::Std { compiler: Compiler { host: a, stage: 2 }, target: a },
compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b },
compile::Std { compiler: Compiler { host: a, stage: 2 }, target: c },
std!(A => A, stage = 0),
std!(A => A, stage = 1),
std!(A => A, stage = 2),
std!(A => B, stage = 1),
std!(A => B, stage = 2),
std!(A => C, stage = 2),
]
);
assert!(!builder.cache.all::<compile::Assemble>().is_empty());
assert_eq!(builder.cache.all::<compile::Assemble>().len(), 5);
assert_eq!(
first(builder.cache.all::<compile::Rustc>()),
&[
compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a },
compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: a },
compile::Rustc { compiler: Compiler { host: a, stage: 2 }, target: a },
compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: b },
compile::Rustc { compiler: Compiler { host: a, stage: 2 }, target: b },
rustc!(A => A, stage = 0),
rustc!(A => A, stage = 1),
rustc!(A => A, stage = 2),
rustc!(A => B, stage = 1),
rustc!(A => B, stage = 2),
]
);
}
......@@ -513,15 +522,10 @@ fn build_with_empty_host() {
builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]);
let a = TargetSelection::from_user("A");
let c = TargetSelection::from_user("C");
assert_eq!(
first(builder.cache.all::<compile::Std>()),
&[
compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
compile::Std { compiler: Compiler { host: a, stage: 2 }, target: c },
]
&[std!(A => A, stage = 0), std!(A => A, stage = 1), std!(A => C, stage = 2),]
);
assert_eq!(
first(builder.cache.all::<compile::Assemble>()),
......@@ -533,10 +537,7 @@ fn build_with_empty_host() {
);
assert_eq!(
first(builder.cache.all::<compile::Rustc>()),
&[
compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a },
compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: a },
]
&[rustc!(A => A, stage = 0), rustc!(A => A, stage = 1),]
);
}
......
......@@ -4,13 +4,12 @@
use std::cmp::{Ord, Ordering, PartialOrd};
use std::collections::HashMap;
use std::convert::AsRef;
use std::ffi::OsStr;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
use std::mem;
use std::ops::Deref;
use std::path::{Path, PathBuf};
use std::path::PathBuf;
use std::sync::Mutex;
// FIXME: replace with std::lazy after it gets stabilized and reaches beta
......@@ -20,15 +19,9 @@
pub struct Interned<T>(usize, PhantomData<*const T>);
impl Default for Interned<String> {
impl<T: Internable + Default> Default for Interned<T> {
fn default() -> Self {
INTERNER.intern_string(String::default())
}
}
impl Default for Interned<PathBuf> {
fn default() -> Self {
INTERNER.intern_path(PathBuf::default())
T::default().intern()
}
}
......@@ -77,87 +70,48 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
}
}
impl fmt::Debug for Interned<String> {
impl<T, U: ?Sized + fmt::Debug> fmt::Debug for Interned<T>
where
Self: Deref<Target = U>,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s: &str = &*self;
f.write_fmt(format_args!("{:?}", s))
}
}
impl fmt::Debug for Interned<PathBuf> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s: &Path = &*self;
let s: &U = &*self;
f.write_fmt(format_args!("{:?}", s))
}
}
impl Hash for Interned<String> {
impl<T: Internable + Hash> Hash for Interned<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
let l = INTERNER.strs.lock().unwrap();
let l = T::intern_cache().lock().unwrap();
l.get(*self).hash(state)
}
}
impl Hash for Interned<PathBuf> {
fn hash<H: Hasher>(&self, state: &mut H) {
let l = INTERNER.paths.lock().unwrap();
l.get(*self).hash(state)
impl<T: Internable + Deref> Deref for Interned<T> {
type Target = T::Target;
fn deref(&self) -> &'static Self::Target {
let l = T::intern_cache().lock().unwrap();
unsafe { mem::transmute::<&Self::Target, &'static Self::Target>(l.get(*self)) }
}
}
impl Deref for Interned<String> {
type Target = str;
fn deref(&self) -> &'static str {
let l = INTERNER.strs.lock().unwrap();
unsafe { mem::transmute::<&str, &'static str>(l.get(*self)) }
impl<T: Internable + AsRef<U>, U: ?Sized> AsRef<U> for Interned<T> {
fn as_ref(&self) -> &'static U {
let l = T::intern_cache().lock().unwrap();
unsafe { mem::transmute::<&U, &'static U>(l.get(*self).as_ref()) }
}
}
impl Deref for Interned<PathBuf> {
type Target = Path;
fn deref(&self) -> &'static Path {
let l = INTERNER.paths.lock().unwrap();
unsafe { mem::transmute::<&Path, &'static Path>(l.get(*self)) }
}
}
impl AsRef<Path> for Interned<PathBuf> {
fn as_ref(&self) -> &'static Path {
let l = INTERNER.paths.lock().unwrap();
unsafe { mem::transmute::<&Path, &'static Path>(l.get(*self)) }
}
}
impl AsRef<Path> for Interned<String> {
fn as_ref(&self) -> &'static Path {
let l = INTERNER.strs.lock().unwrap();
unsafe { mem::transmute::<&Path, &'static Path>(l.get(*self).as_ref()) }
}
}
impl AsRef<OsStr> for Interned<PathBuf> {
fn as_ref(&self) -> &'static OsStr {
let l = INTERNER.paths.lock().unwrap();
unsafe { mem::transmute::<&OsStr, &'static OsStr>(l.get(*self).as_ref()) }
}
}
impl AsRef<OsStr> for Interned<String> {
fn as_ref(&self) -> &'static OsStr {
let l = INTERNER.strs.lock().unwrap();
unsafe { mem::transmute::<&OsStr, &'static OsStr>(l.get(*self).as_ref()) }
}
}
impl PartialOrd<Interned<String>> for Interned<String> {
impl<T: Internable + PartialOrd> PartialOrd for Interned<T> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
let l = INTERNER.strs.lock().unwrap();
let l = T::intern_cache().lock().unwrap();
l.get(*self).partial_cmp(l.get(*other))
}
}
impl Ord for Interned<String> {
impl<T: Internable + Ord> Ord for Interned<T> {
fn cmp(&self, other: &Self) -> Ordering {
let l = INTERNER.strs.lock().unwrap();
let l = T::intern_cache().lock().unwrap();
l.get(*self).cmp(l.get(*other))
}
}
......@@ -208,6 +162,33 @@ fn get(&self, i: Interned<T>) -> &T {
pub struct Interner {
strs: Mutex<TyIntern<String>>,
paths: Mutex<TyIntern<PathBuf>>,
lists: Mutex<TyIntern<Vec<String>>>,
}
trait Internable: Clone + Eq + Hash + 'static {
fn intern_cache() -> &'static Mutex<TyIntern<Self>>;
fn intern(self) -> Interned<Self> {
Self::intern_cache().lock().unwrap().intern(self)
}
}
impl Internable for String {
fn intern_cache() -> &'static Mutex<TyIntern<Self>> {
&INTERNER.strs
}
}
impl Internable for PathBuf {
fn intern_cache() -> &'static Mutex<TyIntern<Self>> {
&INTERNER.paths
}
}
impl Internable for Vec<String> {
fn intern_cache() -> &'static Mutex<TyIntern<Self>> {
&INTERNER.lists
}
}
impl Interner {
......@@ -221,6 +202,10 @@ pub fn intern_string(&self, s: String) -> Interned<String> {
pub fn intern_path(&self, s: PathBuf) -> Interned<PathBuf> {
self.paths.lock().unwrap().intern(s)
}
pub fn intern_list(&self, v: Vec<String>) -> Interned<Vec<String>> {
self.lists.lock().unwrap().intern(v)
}
}
pub static INTERNER: Lazy<Interner> = Lazy::new(Interner::default);
......
......@@ -184,8 +184,8 @@ fn run(self, builder: &Builder<'_>) {
// the sysroot for the compiler to find. Otherwise, we're going to
// fail when building crates that need to generate code (e.g., build
// scripts and their dependencies).
builder.ensure(crate::compile::Std { target: compiler.host, compiler });
builder.ensure(crate::compile::Std { target, compiler });
builder.ensure(crate::compile::Std::new(compiler, compiler.host));
builder.ensure(crate::compile::Std::new(compiler, target));
} else {
builder.ensure(Std { target });
}
......
......@@ -29,10 +29,31 @@
use crate::LLVM_TOOLS;
use crate::{CLang, Compiler, DependencyType, GitRepo, Mode};
#[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Std {
pub target: TargetSelection,
pub compiler: Compiler,
/// Whether to build only a subset of crates in the standard library.
///
/// This shouldn't be used from other steps; see the comment on [`Rustc`].
crates: Interned<Vec<String>>,
}
impl Std {
pub fn new(compiler: Compiler, target: TargetSelection) -> Self {
Self { target, compiler, crates: Default::default() }
}
}
/// Return a `-p=x -p=y` string suitable for passing to a cargo invocation.
fn build_crates_in_set(run: &RunConfig<'_>) -> Interned<Vec<String>> {
let mut crates = Vec::new();
for krate in &run.paths {
let path = krate.assert_single_path();
let crate_name = run.builder.crate_paths[&path.path];
crates.push(format!("-p={crate_name}"));
}
INTERNER.intern_list(crates)
}
impl Step for Std {
......@@ -43,15 +64,22 @@ fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
// When downloading stage1, the standard library has already been copied to the sysroot, so
// there's no need to rebuild it.
let builder = run.builder;
run.all_krates("test")
run.crate_or_deps("test")
.path("library")
.lazy_default_condition(Box::new(|| !builder.download_rustc()))
}
fn make_run(run: RunConfig<'_>) {
// Normally, people will pass *just* library if they pass it.
// But it's possible (although strange) to pass something like `library std core`.
// Build all crates anyway, as if they hadn't passed the other args.
let has_library =
run.paths.iter().any(|set| set.assert_single_path().path.ends_with("library"));
let crates = if has_library { Default::default() } else { build_crates_in_set(&run) };
run.builder.ensure(Std {
compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()),
target: run.target,
crates,
});
}
......@@ -86,7 +114,7 @@ fn run(self, builder: &Builder<'_>) {
let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
if compiler_to_use != compiler {
builder.ensure(Std { compiler: compiler_to_use, target });
builder.ensure(Std::new(compiler_to_use, target));
builder.info(&format!("Uplifting stage1 std ({} -> {})", compiler_to_use.host, target));
// Even if we're not building std this stage, the new sysroot must
......@@ -115,7 +143,7 @@ fn run(self, builder: &Builder<'_>) {
run_cargo(
builder,
cargo,
vec![],
self.crates.to_vec(),
&libstd_stamp(builder, compiler, target),
target_deps,
false,
......@@ -524,6 +552,18 @@ fn run(self, builder: &Builder<'_>) -> Vec<(PathBuf, DependencyType)> {
pub struct Rustc {
pub target: TargetSelection,
pub compiler: Compiler,
/// Whether to build a subset of crates, rather than the whole compiler.
///
/// This should only be requested by the user, not used within rustbuild itself.
/// Using it within rustbuild can lead to confusing situation where lints are replayed
/// in two different steps.
crates: Interned<Vec<String>>,
}
impl Rustc {
pub fn new(compiler: Compiler, target: TargetSelection) -> Self {
Self { target, compiler, crates: Default::default() }
}
}
impl Step for Rustc {
......@@ -532,13 +572,22 @@ impl Step for Rustc {
const DEFAULT: bool = false;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.never()
let mut crates = run.builder.in_tree_crates("rustc-main", None);
for (i, krate) in crates.iter().enumerate() {
if krate.name == "rustc-main" {
crates.swap_remove(i);
break;
}
}
run.crates(crates)
}
fn make_run(run: RunConfig<'_>) {
let crates = build_crates_in_set(&run);
run.builder.ensure(Rustc {
compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()),
target: run.target,
crates,
});
}
......@@ -560,7 +609,7 @@ fn run(self, builder: &Builder<'_>) {
return;
}
builder.ensure(Std { compiler, target });
builder.ensure(Std::new(compiler, target));
if builder.config.keep_stage.contains(&compiler.stage) {
builder.info("Warning: Using a potentially old librustc. This may not behave well.");
......@@ -571,7 +620,7 @@ fn run(self, builder: &Builder<'_>) {
let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
if compiler_to_use != compiler {
builder.ensure(Rustc { compiler: compiler_to_use, target });
builder.ensure(Rustc::new(compiler_to_use, target));
builder
.info(&format!("Uplifting stage1 rustc ({} -> {})", builder.config.build, target));
builder.ensure(RustcLink {
......@@ -583,10 +632,10 @@ fn run(self, builder: &Builder<'_>) {
}
// Ensure that build scripts and proc macros have a std / libproc_macro to link against.
builder.ensure(Std {
compiler: builder.compiler(self.compiler.stage, builder.config.build),
target: builder.config.build,
});
builder.ensure(Std::new(
builder.compiler(self.compiler.stage, builder.config.build),
builder.config.build,
));
let mut cargo = builder.cargo(compiler, Mode::Rustc, SourceType::InTree, target, "build");
rustc_cargo(builder, &mut cargo, target);
......@@ -633,7 +682,7 @@ fn run(self, builder: &Builder<'_>) {
run_cargo(
builder,
cargo,
vec![],
self.crates.to_vec(),
&librustc_stamp(builder, compiler, target),
vec![],
false,
......@@ -821,7 +870,7 @@ fn run(self, builder: &Builder<'_>) {
let target = self.target;
let backend = self.backend;
builder.ensure(Rustc { compiler, target });
builder.ensure(Rustc::new(compiler, target));
if builder.config.keep_stage.contains(&compiler.stage) {
builder.info(
......@@ -1103,7 +1152,7 @@ fn run(self, builder: &Builder<'_>) -> Compiler {
// link to these. (FIXME: Is that correct? It seems to be correct most
// of the time but I think we do link to these for stage2/bin compilers
// when not performing a full bootstrap).
builder.ensure(Rustc { compiler: build_compiler, target: target_compiler.host });
builder.ensure(Rustc::new(build_compiler, target_compiler.host));
for &backend in builder.config.rust_codegen_backends.iter() {
if backend == "llvm" {
......
......@@ -557,7 +557,7 @@ fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
return None;
}
builder.ensure(compile::Std { compiler, target });
builder.ensure(compile::Std::new(compiler, target));
let mut tarball = Tarball::new(builder, "rust-std", &target.triple);
tarball.include_target_in_component_name(true);
......@@ -603,7 +603,7 @@ fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
return None;
}
builder.ensure(compile::Rustc { compiler, target });
builder.ensure(compile::Rustc::new(compiler, target));
let tarball = Tarball::new(builder, "rustc-dev", &target.triple);
......@@ -666,7 +666,7 @@ fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
return None;
}
builder.ensure(compile::Std { compiler, target });
builder.ensure(compile::Std::new(compiler, target));
let src = builder
.stage_out(compiler, Mode::Std)
.join(target.triple)
......
......@@ -534,7 +534,9 @@ impl Step for Rustc {
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let builder = run.builder;
run.krate("rustc-main").path("compiler").default_condition(builder.config.compiler_docs)
run.crate_or_deps("rustc-main")
.path("compiler")
.default_condition(builder.config.compiler_docs)
}
fn make_run(run: RunConfig<'_>) {
......@@ -567,7 +569,7 @@ fn run(self, builder: &Builder<'_>) {
// Build the standard library, so that proc-macros can use it.
// (Normally, only the metadata would be necessary, but proc-macros are special since they run at compile-time.)
let compiler = builder.compiler(stage, builder.config.build);
builder.ensure(compile::Std { compiler, target: builder.config.build });
builder.ensure(compile::Std::new(compiler, builder.config.build));
builder.info(&format!("Documenting stage{} compiler ({})", stage, target));
......@@ -656,7 +658,7 @@ impl Step for $tool {
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let builder = run.builder;
run.krate($should_run).default_condition(builder.config.compiler_docs)
run.crate_or_deps($should_run).default_condition(builder.config.compiler_docs)
}
fn make_run(run: RunConfig<'_>) {
......@@ -683,7 +685,7 @@ fn run(self, builder: &Builder<'_>) {
// FIXME: is there a way to only ensure `check::Rustc` here? Last time I tried it failed
// with strange errors, but only on a full bors test ...
let compiler = builder.compiler(stage, builder.config.build);
builder.ensure(compile::Rustc { compiler, target });
builder.ensure(compile::Rustc::new(compiler, target));
builder.info(
&format!(
......@@ -890,7 +892,7 @@ fn run(self, builder: &Builder<'_>) {
let rustc = builder.rustc(self.compiler);
// The tool runs `rustc` for extracting output examples, so it needs a
// functional sysroot.
builder.ensure(compile::Std { compiler: self.compiler, target: self.target });
builder.ensure(compile::Std::new(self.compiler, self.target));
let mut cmd = builder.tool_cmd(Tool::LintDocs);
cmd.arg("--src");
cmd.arg(builder.src.join("compiler"));
......
......@@ -487,16 +487,14 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
let version = output(cmd.arg("--version"));
let major = version.split('.').next().unwrap();
let lib_name = match llvm_version_suffix {
Some(s) => format!("lib/libLLVM-{}{}.dylib", major, s),
None => format!("lib/libLLVM-{}.dylib", major),
Some(s) => format!("libLLVM-{}{}.dylib", major, s),
None => format!("libLLVM-{}.dylib", major),
};
// The reason why we build the library path from llvm-config is because
// the output of llvm-config depends on its location in the file system.
// Make sure we create the symlink exactly where it's needed.
let llvm_base = build_llvm_config.parent().unwrap().parent().unwrap();
let lib_llvm = llvm_base.join(lib_name);
t!(builder.symlink_file("libLLVM.dylib", &lib_llvm));
let lib_llvm = out_dir.join("build").join("lib").join(lib_name);
if !lib_llvm.exists() {
t!(builder.symlink_file("libLLVM.dylib", &lib_llvm));
}
}
t!(stamp.write());
......
......@@ -225,7 +225,7 @@ fn make_run(run: RunConfig<'_>) {
/// test` to ensure that we don't regress the test suites there.
fn run(self, builder: &Builder<'_>) {
let compiler = builder.compiler(self.stage, self.host);
builder.ensure(compile::Rustc { compiler, target: compiler.host });
builder.ensure(compile::Rustc::new(compiler, compiler.host));
let cargo = builder.ensure(tool::Cargo { compiler, target: compiler.host });
// Note that this is a short, cryptic, and not scoped directory name. This
......@@ -603,7 +603,7 @@ fn run(self, builder: &Builder<'_>) {
// We need `ToolStd` for the locally-built sysroot because
// compiletest uses unstable features of the `test` crate.
builder.ensure(compile::Std { compiler, target: host });
builder.ensure(compile::Std::new(compiler, host));
let cargo = tool::prepare_tool_cargo(
builder,
compiler,
......@@ -896,7 +896,7 @@ fn run(self, builder: &Builder<'_>) {
let nodejs = builder.config.nodejs.as_ref().expect("nodejs isn't available");
let npm = builder.config.npm.as_ref().expect("npm isn't available");
builder.ensure(compile::Std { compiler: self.compiler, target: self.target });
builder.ensure(compile::Std::new(self.compiler, self.target));
// The goal here is to check if the necessary packages are installed, and if not, we
// panic.
......@@ -1273,12 +1273,12 @@ fn run(self, builder: &Builder<'_>) {
}
if suite.ends_with("fulldeps") {
builder.ensure(compile::Rustc { compiler, target });
builder.ensure(compile::Rustc::new(compiler, target));
}
builder.ensure(compile::Std { compiler, target });
builder.ensure(compile::Std::new(compiler, target));
// ensure that `libproc_macro` is available on the host.
builder.ensure(compile::Std { compiler, target: compiler.host });
builder.ensure(compile::Std::new(compiler, compiler.host));
// Also provide `rust_test_helpers` for the host.
builder.ensure(native::TestHelpers { target: compiler.host });
......@@ -1643,7 +1643,7 @@ impl BookTest {
fn run_ext_doc(self, builder: &Builder<'_>) {
let compiler = self.compiler;
builder.ensure(compile::Std { compiler, target: compiler.host });
builder.ensure(compile::Std::new(compiler, compiler.host));
// mdbook just executes a binary named "rustdoc", so we need to update
// PATH so that it points to our rustdoc.
......@@ -1671,7 +1671,7 @@ fn run_ext_doc(self, builder: &Builder<'_>) {
fn run_local_doc(self, builder: &Builder<'_>) {
let compiler = self.compiler;
builder.ensure(compile::Std { compiler, target: compiler.host });
builder.ensure(compile::Std::new(compiler, compiler.host));
// Do a breadth-first traversal of the `src/doc` directory and just run
// tests for all files that end in `*.md`
......@@ -1790,7 +1790,7 @@ fn run(self, builder: &Builder<'_>) {
builder.run_quiet(&mut tool);
// The tests themselves need to link to std, so make sure it is
// available.
builder.ensure(compile::Std { compiler, target: compiler.host });
builder.ensure(compile::Std::new(compiler, compiler.host));
markdown_test(builder, compiler, &output);
}
}
......@@ -1867,7 +1867,7 @@ impl Step for CrateLibrustc {
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.krate("rustc-main")
run.crate_or_deps("rustc-main")
}
fn make_run(run: RunConfig<'_>) {
......@@ -1909,7 +1909,7 @@ impl Step for Crate {
const DEFAULT: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.krate("test")
run.crate_or_deps("test")
}
fn make_run(run: RunConfig<'_>) {
......@@ -1940,7 +1940,7 @@ fn run(self, builder: &Builder<'_>) {
let mode = self.mode;
let test_kind = self.test_kind;
builder.ensure(compile::Std { compiler, target });
builder.ensure(compile::Std::new(compiler, target));
builder.ensure(RemoteCopyLibs { compiler, target });
// If we're not doing a full bootstrap but we're testing a stage2
......@@ -2062,7 +2062,7 @@ fn run(self, builder: &Builder<'_>) {
// isn't really necessary.
builder.compiler_for(builder.top_stage, target, target)
};
builder.ensure(compile::Rustc { compiler, target });
builder.ensure(compile::Rustc::new(compiler, target));
let mut cargo = tool::prepare_tool_cargo(
builder,
......@@ -2177,7 +2177,7 @@ fn run(self, builder: &Builder<'_>) {
// `compiler`, then it would cause rustdoc to be built *again*, which
// isn't really necessary.
let compiler = builder.compiler_for(builder.top_stage, target, target);
builder.ensure(compile::Rustc { compiler, target });
builder.ensure(compile::Rustc::new(compiler, target));
let mut cargo = tool::prepare_tool_cargo(
builder,
......@@ -2245,7 +2245,7 @@ fn run(self, builder: &Builder<'_>) {
return;
}
builder.ensure(compile::Std { compiler, target });
builder.ensure(compile::Std::new(compiler, target));
builder.info(&format!("REMOTE copy libs to emulator ({})", target));
......@@ -2415,7 +2415,7 @@ fn make_run(run: RunConfig<'_>) {
/// Tests the Platform Support page in the rustc book.
fn run(self, builder: &Builder<'_>) {
builder.ensure(compile::Std { compiler: self.compiler, target: self.compiler.host });
builder.ensure(compile::Std::new(self.compiler, self.compiler.host));
let mut cargo = tool::prepare_tool_cargo(
builder,
self.compiler,
......
......@@ -51,10 +51,10 @@ fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
match self.mode {
Mode::ToolRustc => {
builder.ensure(compile::Std { compiler, target: compiler.host });
builder.ensure(compile::Rustc { compiler, target });
builder.ensure(compile::Std::new(compiler, compiler.host));
builder.ensure(compile::Rustc::new(compiler, target));
}
Mode::ToolStd => builder.ensure(compile::Std { compiler, target }),
Mode::ToolStd => builder.ensure(compile::Std::new(compiler, target)),
Mode::ToolBootstrap => {} // uses downloaded stage0 compiler libs
_ => panic!("unexpected Mode for tool build"),
}
......@@ -512,8 +512,8 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
// When using `download-rustc` and a stage0 build_compiler, copying rustc doesn't actually
// build stage0 libstd (because the libstd in sysroot has the wrong ABI). Explicitly build
// it.
builder.ensure(compile::Std { compiler: build_compiler, target: target_compiler.host });
builder.ensure(compile::Rustc { compiler: build_compiler, target: target_compiler.host });
builder.ensure(compile::Std::new(build_compiler, target_compiler.host));
builder.ensure(compile::Rustc::new(build_compiler, target_compiler.host));
// NOTE: this implies that `download-rustc` is pretty useless when compiling with the stage0
// compiler, since you do just as much work.
if !builder.config.dry_run && builder.download_rustc() && build_compiler.stage == 0 {
......
Subproject commit efbafdba3618487fbc9305318fcab9775132ac15
Subproject commit cf2653a5ca553cbbb4a17f1a7db1947820f6a775
Subproject commit e17dcef5e96346ee3d7fa56820ddc7e5c39636bc
Subproject commit 766979590da8100998f0d662499d4a901d8d1640
Subproject commit 3a43983b76174342b7dbd3e12ea2c49f762e52be
Subproject commit 70db9e4189f64d1d8e2451b1046111fb356b6dc2
Subproject commit 1095df2a5850f2d345fad43a30633133365875ba
Subproject commit 83724ca387a2a1cd3e8d848f62820020760e358b
Subproject commit 048d925f0a955aac601c4160c0e7f05771bcf63b
Subproject commit eb83839e903a0a8f1406f7e941886273f189b26b
......@@ -146,6 +146,10 @@ pub(crate) fn is_for_html(&self) -> bool {
pub(crate) fn reserve(&mut self, additional: usize) {
self.buffer.reserve(additional)
}
pub(crate) fn len(&self) -> usize {
self.buffer.len()
}
}
fn comma_sep<T: fmt::Display>(
......
......@@ -62,6 +62,17 @@ struct ItemVars<'a> {
src_href: Option<&'a str>,
}
/// Calls `print_where_clause` and returns `true` if a `where` clause was generated.
fn print_where_clause_and_check<'a, 'tcx: 'a>(
buffer: &mut Buffer,
gens: &'a clean::Generics,
cx: &'a Context<'tcx>,
) -> bool {
let len_before = buffer.len();
write!(buffer, "{}", print_where_clause(gens, cx, 0, true));
len_before != buffer.len()
}
pub(super) fn print_item(
cx: &mut Context<'_>,
item: &clean::Item,
......@@ -1152,17 +1163,21 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
render_attributes_in_pre(w, it, "");
write!(
w,
"{}enum {}{}{}",
"{}enum {}{}",
it.visibility.print_with_space(it.item_id, cx),
it.name.unwrap(),
e.generics.print(cx),
print_where_clause(&e.generics, cx, 0, true),
);
if !print_where_clause_and_check(w, &e.generics, cx) {
// If there wasn't a `where` clause, we add a whitespace.
w.write_str(" ");
}
let variants_stripped = e.has_stripped_entries();
if count_variants == 0 && !variants_stripped {
w.write_str(" {}");
w.write_str("{}");
} else {
w.write_str(" {\n");
w.write_str("{\n");
let toggle = should_hide_fields(count_variants);
if toggle {
toggle_open(w, format_args!("{} variants", count_variants));
......@@ -1643,13 +1658,21 @@ fn render_union(
tab: &str,
cx: &Context<'_>,
) {
write!(w, "{}union {}", it.visibility.print_with_space(it.item_id, cx), it.name.unwrap());
if let Some(g) = g {
write!(w, "{}", g.print(cx));
write!(w, "{}", print_where_clause(g, cx, 0, true));
write!(w, "{}union {}", it.visibility.print_with_space(it.item_id, cx), it.name.unwrap(),);
let where_displayed = g
.map(|g| {
write!(w, "{}", g.print(cx));
print_where_clause_and_check(w, g, cx)
})
.unwrap_or(false);
// If there wasn't a `where` clause, we add a whitespace.
if !where_displayed {
w.write_str(" ");
}
write!(w, " {{\n{}", tab);
write!(w, "{{\n{}", tab);
let count_fields =
fields.iter().filter(|f| matches!(*f.kind, clean::StructFieldItem(..))).count();
let toggle = should_hide_fields(count_fields);
......@@ -1701,10 +1724,14 @@ fn render_struct(
}
match ty {
CtorKind::Fictive => {
if let Some(g) = g {
write!(w, "{}", print_where_clause(g, cx, 0, true),)
let where_diplayed = g.map(|g| print_where_clause_and_check(w, g, cx)).unwrap_or(false);
// If there wasn't a `where` clause, we add a whitespace.
if !where_diplayed {
w.write_str(" {");
} else {
w.write_str("{");
}
w.write_str(" {");
let count_fields =
fields.iter().filter(|f| matches!(*f.kind, clean::StructFieldItem(..))).count();
let has_visible_fields = count_fields > 0;
......@@ -1759,7 +1786,7 @@ fn render_struct(
}
w.write_str(")");
if let Some(g) = g {
write!(w, "{}", print_where_clause(g, cx, 0, false),)
write!(w, "{}", print_where_clause(g, cx, 0, false));
}
// We only want a ";" when we are displaying a tuple struct, not a variant tuple struct.
if structhead {
......@@ -1769,7 +1796,7 @@ fn render_struct(
CtorKind::Const => {
// Needed for PhantomData.
if let Some(g) = g {
write!(w, "{}", print_where_clause(g, cx, 0, false),)
write!(w, "{}", print_where_clause(g, cx, 0, false));
}
w.write_str(";");
}
......
<div class="docblock item-decl"><pre class="rust enum"><code>pub enum Cow&lt;'a, B:&#160;?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a&gt; <span class="where fmt-newline">where<br />&#160;&#160;&#160;&#160;B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt;,&#160;</span>{
Borrowed(<a class="primitive" href="{{channel}}/std/primitive.reference.html">&amp;'a </a>B),
Whatever(<a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>),
}</code></pre></div>
<div class="docblock item-decl"><pre class="rust enum"><code>pub enum Cow2&lt;'a, B:&#160;?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt; + 'a&gt; {
Borrowed(<a class="primitive" href="{{channel}}/std/primitive.reference.html">&amp;'a </a>B),
Whatever(<a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>),
}</code></pre></div>
// This test ensures there is no whitespace before the first brace of
// trait, enum, struct and union items when they have a where clause.
#![crate_name = "foo"]
// @has 'foo/trait.ToOwned.html'
// @snapshot trait - '//*[@class="docblock item-decl"]'
pub trait ToOwned<T>
where T: Clone
{
type Owned;
fn to_owned(&self) -> Self::Owned;
fn whatever(&self) -> T;
}
// @has 'foo/trait.ToOwned2.html'
// @snapshot trait2 - '//*[@class="docblock item-decl"]'
// There should be a whitespace before `{` in this case!
pub trait ToOwned2<T: Clone> {
type Owned;
fn to_owned(&self) -> Self::Owned;
fn whatever(&self) -> T;
}
// @has 'foo/enum.Cow.html'
// @snapshot enum - '//*[@class="docblock item-decl"]'
pub enum Cow<'a, B: ?Sized + 'a>
where
B: ToOwned<Clone>,
{
Borrowed(&'a B),
Whatever(u32),
}
// @has 'foo/enum.Cow2.html'
// @snapshot enum2 - '//*[@class="docblock item-decl"]'
// There should be a whitespace before `{` in this case!
pub enum Cow2<'a, B: ?Sized + ToOwned<Clone> + 'a> {
Borrowed(&'a B),
Whatever(u32),
}
// @has 'foo/struct.Struct.html'
// @snapshot struct - '//*[@class="docblock item-decl"]'
pub struct Struct<'a, B: ?Sized + 'a>
where
B: ToOwned<Clone>,
{
pub a: &'a B,
pub b: u32,
}
// @has 'foo/struct.Struct2.html'
// @snapshot struct2 - '//*[@class="docblock item-decl"]'
// There should be a whitespace before `{` in this case!
pub struct Struct2<'a, B: ?Sized + ToOwned<Clone> + 'a> {
pub a: &'a B,
pub b: u32,
}
// @has 'foo/union.Union.html'
// @snapshot union - '//*[@class="docblock item-decl"]'
pub union Union<'a, B: ?Sized + 'a>
where
B: ToOwned<Clone>,
{
a: &'a B,
b: u32,
}
// @has 'foo/union.Union2.html'
// @snapshot union2 - '//*[@class="docblock item-decl"]'
// There should be a whitespace before `{` in this case!
pub union Union2<'a, B: ?Sized + ToOwned<Clone> + 'a> {
a: &'a B,
b: u32,
}
<div class="docblock item-decl"><pre class="rust struct"><code>pub struct Struct&lt;'a, B:&#160;?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a&gt; <span class="where fmt-newline">where<br />&#160;&#160;&#160;&#160;B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt;,&#160;</span>{
pub a: <a class="primitive" href="{{channel}}/std/primitive.reference.html">&amp;'a </a>B,
pub b: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>,
}</code></pre></div>
<div class="docblock item-decl"><pre class="rust struct"><code>pub struct Struct2&lt;'a, B:&#160;?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt; + 'a&gt; {
pub a: <a class="primitive" href="{{channel}}/std/primitive.reference.html">&amp;'a </a>B,
pub b: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>,
}</code></pre></div>
<div class="docblock item-decl"><pre class="rust trait"><code>pub trait ToOwned&lt;T&gt; <span class="where fmt-newline">where<br />&#160;&#160;&#160;&#160;T: <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>,&#160;</span>{
type <a href="#associatedtype.Owned" class="associatedtype">Owned</a>;
fn <a href="#tymethod.to_owned" class="fnname">to_owned</a>(&amp;self) -&gt; Self::<a class="associatedtype" href="trait.ToOwned.html#associatedtype.Owned" title="type foo::ToOwned::Owned">Owned</a>;
<span class="item-spacer" /> fn <a href="#tymethod.whatever" class="fnname">whatever</a>(&amp;self) -&gt; T;
}</code></pre></div>
<div class="docblock item-decl"><pre class="rust trait"><code>pub trait ToOwned2&lt;T:&#160;<a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt; {
type <a href="#associatedtype.Owned" class="associatedtype">Owned</a>;
fn <a href="#tymethod.to_owned" class="fnname">to_owned</a>(&amp;self) -&gt; Self::<a class="associatedtype" href="trait.ToOwned2.html#associatedtype.Owned" title="type foo::ToOwned2::Owned">Owned</a>;
<span class="item-spacer" /> fn <a href="#tymethod.whatever" class="fnname">whatever</a>(&amp;self) -&gt; T;
}</code></pre></div>
<div class="docblock item-decl"><pre class="rust union"><code>pub union Union&lt;'a, B:&#160;?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a&gt; <span class="where fmt-newline">where<br />&#160;&#160;&#160;&#160;B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt;,&#160;</span>{
/* private fields */
}</code></pre></div>
<div class="docblock item-decl"><pre class="rust union"><code>pub union Union2&lt;'a, B:&#160;?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt; + 'a&gt; {
/* private fields */
}</code></pre></div>
......@@ -11,5 +11,15 @@ enum Aligned {
fn main() {
let aligned = Aligned::Zero;
let fo = aligned as u8;
println!("foo {}",fo);
println!("foo {}", fo);
assert_eq!(fo, 0);
println!("{}", tou8(Aligned::Zero));
assert_eq!(tou8(Aligned::Zero), 0);
}
#[inline(never)]
fn tou8(al: Aligned) -> u8 {
// Cast behind a function call so ConstProp does not see it
// (so that we can test codegen).
al as u8
}
// normalize-stderr-test "pref: Align\([1-8] bytes\)" -> "pref: $$PREF_ALIGN"
#![crate_type = "lib"]
#![feature(rustc_attrs)]
// This cannot use `Scalar` abi since there is padding.
#[rustc_layout(debug)]
#[repr(align(8))]
pub enum Aligned1 { //~ ERROR: layout_of
Zero = 0,
One = 1,
}
// This should use `Scalar` abi.
#[rustc_layout(debug)]
#[repr(align(1))]
pub enum Aligned2 { //~ ERROR: layout_of
Zero = 0,
One = 1,
}
error: layout_of(Aligned1) = Layout {
fields: Arbitrary {
offsets: [
Size(0 bytes),
],
memory_index: [
0,
],
},
variants: Multiple {
tag: Initialized {
value: Int(
I8,
false,
),
valid_range: 0..=1,
},
tag_encoding: Direct,
tag_field: 0,
variants: [
Layout {
fields: Arbitrary {
offsets: [],
memory_index: [],
},
variants: Single {
index: 0,
},
abi: Aggregate {
sized: true,
},
largest_niche: None,
align: AbiAndPrefAlign {
abi: Align(8 bytes),
pref: $PREF_ALIGN,
},
size: Size(8 bytes),
},
Layout {
fields: Arbitrary {
offsets: [],
memory_index: [],
},
variants: Single {
index: 1,
},
abi: Aggregate {
sized: true,
},
largest_niche: None,
align: AbiAndPrefAlign {
abi: Align(8 bytes),
pref: $PREF_ALIGN,
},
size: Size(8 bytes),
},
],
},
abi: Aggregate {
sized: true,
},
largest_niche: Some(
Niche {
offset: Size(0 bytes),
value: Int(
I8,
false,
),
valid_range: 0..=1,
},
),
align: AbiAndPrefAlign {
abi: Align(8 bytes),
pref: $PREF_ALIGN,
},
size: Size(8 bytes),
}
--> $DIR/issue-96185-overaligned-enum.rs:8:1
|
LL | pub enum Aligned1 {
| ^^^^^^^^^^^^^^^^^
error: layout_of(Aligned2) = Layout {
fields: Arbitrary {
offsets: [
Size(0 bytes),
],
memory_index: [
0,
],
},
variants: Multiple {
tag: Initialized {
value: Int(
I8,
false,
),
valid_range: 0..=1,
},
tag_encoding: Direct,
tag_field: 0,
variants: [
Layout {
fields: Arbitrary {
offsets: [],
memory_index: [],
},
variants: Single {
index: 0,
},
abi: Aggregate {
sized: true,
},
largest_niche: None,
align: AbiAndPrefAlign {
abi: Align(1 bytes),
pref: $PREF_ALIGN,
},
size: Size(1 bytes),
},
Layout {
fields: Arbitrary {
offsets: [],
memory_index: [],
},
variants: Single {
index: 1,
},
abi: Aggregate {
sized: true,
},
largest_niche: None,
align: AbiAndPrefAlign {
abi: Align(1 bytes),
pref: $PREF_ALIGN,
},
size: Size(1 bytes),
},
],
},
abi: Scalar(
Initialized {
value: Int(
I8,
false,
),
valid_range: 0..=1,
},
),
largest_niche: Some(
Niche {
offset: Size(0 bytes),
value: Int(
I8,
false,
),
valid_range: 0..=1,
},
),
align: AbiAndPrefAlign {
abi: Align(1 bytes),
pref: $PREF_ALIGN,
},
size: Size(1 bytes),
}
--> $DIR/issue-96185-overaligned-enum.rs:16:1
|
LL | pub enum Aligned2 {
| ^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册