1
Fork 0

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
This commit is contained in:
bors 2022-07-05 23:12:34 +00:00
commit f342bea9d1
31 changed files with 605 additions and 218 deletions

View file

@ -1418,9 +1418,9 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
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.

View file

@ -199,14 +199,16 @@ impl<T: JoinSemiLattice> MeetSemiLattice for Dual<T> {
}
/// 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

View file

@ -13,7 +13,6 @@ use std::process::{Command, Stdio};
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::tool::{self, SourceType};
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 @@ impl StepDescription {
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 @@ impl<'a> ShouldRun<'a> {
/// 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 @@ impl<'a> Builder<'a> {
match kind {
Kind::Build => describe!(
compile::Std,
compile::Rustc,
compile::Assemble,
compile::CodegenBackend,
compile::StartupObjects,

View file

@ -57,6 +57,24 @@ fn check_cli<const N: usize>(paths: [&str; N]) {
);
}
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 @@ mod defaults {
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 @@ mod defaults {
// - 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 @@ mod defaults {
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 @@ mod defaults {
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 @@ mod defaults {
);
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 @@ mod dist {
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 @@ mod dist {
#[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 @@ mod dist {
);
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 @@ mod dist {
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 @@ mod dist {
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 @@ mod dist {
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 @@ mod dist {
);
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),]
);
}

View file

@ -4,13 +4,12 @@ use std::cell::RefCell;
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 @@ use crate::builder::Step;
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 @@ impl fmt::Display for Interned<String> {
}
}
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 @@ impl<T: Hash + Clone + Eq> TyIntern<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 @@ impl Interner {
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);

View file

@ -184,8 +184,8 @@ impl Step for Rustc {
// 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 });
}

View file

@ -29,10 +29,31 @@ use crate::util::{exe, is_debug_info, is_dylib, output, symlink_dir, t, up_to_da
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 @@ impl Step for Std {
// 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 @@ impl Step for Std {
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 @@ impl Step for Std {
run_cargo(
builder,
cargo,
vec![],
self.crates.to_vec(),
&libstd_stamp(builder, compiler, target),
target_deps,
false,
@ -524,6 +552,18 @@ impl Step for StartupObjects {
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 @@ impl Step for Rustc {
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 @@ impl Step for Rustc {
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 @@ impl Step for Rustc {
}
// 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 @@ impl Step for Rustc {
run_cargo(
builder,
cargo,
vec![],
self.crates.to_vec(),
&librustc_stamp(builder, compiler, target),
vec![],
false,
@ -821,7 +870,7 @@ impl Step for CodegenBackend {
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 @@ impl Step for Assemble {
// 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" {

View file

@ -557,7 +557,7 @@ impl Step for Std {
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 @@ impl Step for RustcDev {
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 @@ impl Step for Analysis {
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)

View file

@ -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 @@ impl Step for Rustc {
// 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 @@ macro_rules! tool_doc {
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 @@ macro_rules! tool_doc {
// 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 @@ impl Step for RustcBook {
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"));

View file

@ -487,16 +487,14 @@ impl Step for Llvm {
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());

View file

@ -225,7 +225,7 @@ impl Step for Cargotest {
/// 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 @@ impl Step for CompiletestTest {
// 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 @@ impl Step for RustdocGUI {
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 @@ note: if you're sure you want to do this, please open an issue as to why. In the
}
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 @@ impl BookTest {
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 @@ impl Step for ErrorIndex {
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 @@ impl Step for Crate {
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 @@ impl Step for CrateRustdoc {
// 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 @@ impl Step for CrateRustdocJsonTypes {
// `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 @@ impl Step for RemoteCopyLibs {
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 @@ impl Step for TierCheck {
/// 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,

View file

@ -51,10 +51,10 @@ impl Step for ToolBuild {
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 @@ impl Step for Rustdoc {
// 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 {

@ -1 +1 @@
Subproject commit efbafdba3618487fbc9305318fcab9775132ac15
Subproject commit cf2653a5ca553cbbb4a17f1a7db1947820f6a775

@ -1 +1 @@
Subproject commit e17dcef5e96346ee3d7fa56820ddc7e5c39636bc
Subproject commit 766979590da8100998f0d662499d4a901d8d1640

@ -1 +1 @@
Subproject commit 3a43983b76174342b7dbd3e12ea2c49f762e52be
Subproject commit 70db9e4189f64d1d8e2451b1046111fb356b6dc2

@ -1 +1 @@
Subproject commit 1095df2a5850f2d345fad43a30633133365875ba
Subproject commit 83724ca387a2a1cd3e8d848f62820020760e358b

@ -1 +1 @@
Subproject commit 048d925f0a955aac601c4160c0e7f05771bcf63b
Subproject commit eb83839e903a0a8f1406f7e941886273f189b26b

View file

@ -146,6 +146,10 @@ impl Buffer {
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>(

View file

@ -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(";");
}

View file

@ -0,0 +1,4 @@
<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>

View file

@ -0,0 +1,4 @@
<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>

View file

@ -0,0 +1,77 @@
// 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,
}

View file

@ -0,0 +1,4 @@
<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>

View file

@ -0,0 +1,4 @@
<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>

View file

@ -0,0 +1,6 @@
<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>

View file

@ -0,0 +1,6 @@
<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>

View file

@ -0,0 +1,3 @@
<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>

View file

@ -0,0 +1,3 @@
<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>

View file

@ -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
}

View file

@ -0,0 +1,19 @@
// 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,
}

View file

@ -0,0 +1,172 @@
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