Auto merge of #89435 - Manishearth:rollup-vh2ih7k, r=Manishearth
Rollup of 6 pull requests Successful merges: - #87868 (Added -Z randomize-layout flag) - #88820 (Add `pie` as another `relocation-model` value) - #89029 (feat(rustc_parse): recover from pre-RFC-2000 const generics syntax) - #89322 (Reapply "Remove optimization_fuel_crate from Session") - #89340 (Improve error message for `printf`-style format strings) - #89415 (Correct caller/callsite confusion in inliner message) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
b6057bf7b7
21
Cargo.lock
21
Cargo.lock
@ -1660,7 +1660,7 @@ checksum = "3ca8957e71f04a205cb162508f9326aea04676c8dfd0711220190d6b83664f3f"
|
||||
dependencies = [
|
||||
"bitmaps",
|
||||
"rand_core 0.5.1",
|
||||
"rand_xoshiro",
|
||||
"rand_xoshiro 0.4.0",
|
||||
"sized-chunks",
|
||||
"typenum",
|
||||
"version_check",
|
||||
@ -2256,7 +2256,7 @@ dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"measureme",
|
||||
"rand 0.8.3",
|
||||
"rand 0.8.4",
|
||||
"rustc-workspace-hack",
|
||||
"rustc_version",
|
||||
"shell-escape",
|
||||
@ -2852,9 +2852,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.3"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e"
|
||||
checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha 0.3.0",
|
||||
@ -2945,6 +2945,15 @@ dependencies = [
|
||||
"rand_core 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_xoshiro"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa"
|
||||
dependencies = [
|
||||
"rand_core 0.6.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.3.1"
|
||||
@ -4087,6 +4096,8 @@ dependencies = [
|
||||
"either",
|
||||
"gsgdt",
|
||||
"polonius-engine",
|
||||
"rand 0.8.4",
|
||||
"rand_xoshiro 0.6.0",
|
||||
"rustc-rayon-core",
|
||||
"rustc_apfloat",
|
||||
"rustc_arena",
|
||||
@ -5097,7 +5108,7 @@ checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"rand 0.8.3",
|
||||
"rand 0.8.4",
|
||||
"redox_syscall",
|
||||
"remove_dir_all",
|
||||
"winapi",
|
||||
|
@ -1154,11 +1154,12 @@ macro_rules! check_foreign {
|
||||
// account for `"` and account for raw strings `r#`
|
||||
let padding = str_style.map(|i| i + 2).unwrap_or(1);
|
||||
for sub in foreign::$kind::iter_subs(fmt_str, padding) {
|
||||
let trn = match sub.translate() {
|
||||
Some(trn) => trn,
|
||||
let (trn, success) = match sub.translate() {
|
||||
Ok(trn) => (trn, true),
|
||||
Err(Some(msg)) => (msg, false),
|
||||
|
||||
// If it has no translation, don't call it out specifically.
|
||||
None => continue,
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
let pos = sub.position();
|
||||
@ -1175,9 +1176,24 @@ macro_rules! check_foreign {
|
||||
|
||||
if let Some(inner_sp) = pos {
|
||||
let sp = fmt_sp.from_inner(inner_sp);
|
||||
suggestions.push((sp, trn));
|
||||
|
||||
if success {
|
||||
suggestions.push((sp, trn));
|
||||
} else {
|
||||
diag.span_note(
|
||||
sp,
|
||||
&format!("format specifiers use curly braces, and {}", trn),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
diag.help(&format!("`{}` should be written as `{}`", sub, trn));
|
||||
if success {
|
||||
diag.help(&format!("`{}` should be written as `{}`", sub, trn));
|
||||
} else {
|
||||
diag.note(&format!(
|
||||
"`{}` should use curly braces, and {}",
|
||||
sub, trn
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
pub mod printf {
|
||||
pub(crate) mod printf {
|
||||
use super::strcursor::StrCursor as Cur;
|
||||
use rustc_span::InnerSpan;
|
||||
|
||||
@ -36,10 +36,10 @@ pub fn set_position(&mut self, start: usize, end: usize) {
|
||||
///
|
||||
/// This ignores cases where the substitution does not have an exact equivalent, or where
|
||||
/// the substitution would be unnecessary.
|
||||
pub fn translate(&self) -> Option<String> {
|
||||
pub fn translate(&self) -> Result<String, Option<String>> {
|
||||
match *self {
|
||||
Substitution::Format(ref fmt) => fmt.translate(),
|
||||
Substitution::Escape => None,
|
||||
Substitution::Escape => Err(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -68,9 +68,9 @@ pub struct Format<'a> {
|
||||
impl Format<'_> {
|
||||
/// Translate this directive into an equivalent Rust formatting directive.
|
||||
///
|
||||
/// Returns `None` in cases where the `printf` directive does not have an exact Rust
|
||||
/// Returns `Err` in cases where the `printf` directive does not have an exact Rust
|
||||
/// equivalent, rather than guessing.
|
||||
pub fn translate(&self) -> Option<String> {
|
||||
pub fn translate(&self) -> Result<String, Option<String>> {
|
||||
use std::fmt::Write;
|
||||
|
||||
let (c_alt, c_zero, c_left, c_plus) = {
|
||||
@ -84,7 +84,12 @@ pub fn translate(&self) -> Option<String> {
|
||||
'0' => c_zero = true,
|
||||
'-' => c_left = true,
|
||||
'+' => c_plus = true,
|
||||
_ => return None,
|
||||
_ => {
|
||||
return Err(Some(format!(
|
||||
"the flag `{}` is unknown or unsupported",
|
||||
c
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
(c_alt, c_zero, c_left, c_plus)
|
||||
@ -104,7 +109,9 @@ pub fn translate(&self) -> Option<String> {
|
||||
let width = match self.width {
|
||||
Some(Num::Next) => {
|
||||
// NOTE: Rust doesn't support this.
|
||||
return None;
|
||||
return Err(Some(
|
||||
"you have to use a positional or named parameter for the width".to_string(),
|
||||
));
|
||||
}
|
||||
w @ Some(Num::Arg(_)) => w,
|
||||
w @ Some(Num::Num(_)) => w,
|
||||
@ -125,13 +132,21 @@ pub fn translate(&self) -> Option<String> {
|
||||
"p" => (Some(self.type_), false, true),
|
||||
"g" => (Some("e"), true, false),
|
||||
"G" => (Some("E"), true, false),
|
||||
_ => return None,
|
||||
_ => {
|
||||
return Err(Some(format!(
|
||||
"the conversion specifier `{}` is unknown or unsupported",
|
||||
self.type_
|
||||
)));
|
||||
}
|
||||
};
|
||||
|
||||
let (fill, width, precision) = match (is_int, width, precision) {
|
||||
(true, Some(_), Some(_)) => {
|
||||
// Rust can't duplicate this insanity.
|
||||
return None;
|
||||
return Err(Some(
|
||||
"width and precision cannot both be specified for integer conversions"
|
||||
.to_string(),
|
||||
));
|
||||
}
|
||||
(true, None, Some(p)) => (Some("0"), Some(p), None),
|
||||
(true, w, None) => (fill, w, None),
|
||||
@ -169,7 +184,17 @@ pub fn translate(&self) -> Option<String> {
|
||||
s.push('{');
|
||||
|
||||
if let Some(arg) = self.parameter {
|
||||
write!(s, "{}", arg.checked_sub(1)?).ok()?;
|
||||
match write!(
|
||||
s,
|
||||
"{}",
|
||||
match arg.checked_sub(1) {
|
||||
Some(a) => a,
|
||||
None => return Err(None),
|
||||
}
|
||||
) {
|
||||
Err(_) => return Err(None),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
if has_options {
|
||||
@ -199,12 +224,18 @@ pub fn translate(&self) -> Option<String> {
|
||||
}
|
||||
|
||||
if let Some(width) = width {
|
||||
width.translate(&mut s).ok()?;
|
||||
match width.translate(&mut s) {
|
||||
Err(_) => return Err(None),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(precision) = precision {
|
||||
s.push('.');
|
||||
precision.translate(&mut s).ok()?;
|
||||
match precision.translate(&mut s) {
|
||||
Err(_) => return Err(None),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(type_) = type_ {
|
||||
@ -213,7 +244,7 @@ pub fn translate(&self) -> Option<String> {
|
||||
}
|
||||
|
||||
s.push('}');
|
||||
Some(s)
|
||||
Ok(s)
|
||||
}
|
||||
}
|
||||
|
||||
@ -623,11 +654,11 @@ pub fn set_position(&mut self, start: usize, end: usize) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn translate(&self) -> Option<String> {
|
||||
pub fn translate(&self) -> Result<String, Option<String>> {
|
||||
match *self {
|
||||
Substitution::Ordinal(n, _) => Some(format!("{{{}}}", n)),
|
||||
Substitution::Name(n, _) => Some(format!("{{{}}}", n)),
|
||||
Substitution::Escape(_) => None,
|
||||
Substitution::Ordinal(n, _) => Ok(format!("{{{}}}", n)),
|
||||
Substitution::Name(n, _) => Ok(format!("{{{}}}", n)),
|
||||
Substitution::Escape(_) => Err(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
macro_rules! assert_eq_pnsat {
|
||||
($lhs:expr, $rhs:expr) => {
|
||||
assert_eq!(
|
||||
pns($lhs).and_then(|(s, _)| s.translate()),
|
||||
pns($lhs).and_then(|(s, _)| s.translate().ok()),
|
||||
$rhs.map(<String as From<&str>>::from)
|
||||
)
|
||||
};
|
||||
@ -98,7 +98,7 @@ macro_rules! assert_pns_eq_sub {
|
||||
#[test]
|
||||
fn test_iter() {
|
||||
let s = "The %d'th word %% is: `%.*s` %!\n";
|
||||
let subs: Vec<_> = iter_subs(s, 0).map(|sub| sub.translate()).collect();
|
||||
let subs: Vec<_> = iter_subs(s, 0).map(|sub| sub.translate().ok()).collect();
|
||||
assert_eq!(
|
||||
subs.iter().map(|ms| ms.as_ref().map(|s| &s[..])).collect::<Vec<_>>(),
|
||||
vec![Some("{}"), None, Some("{:.*}"), None]
|
||||
|
@ -3,7 +3,7 @@
|
||||
macro_rules! assert_eq_pnsat {
|
||||
($lhs:expr, $rhs:expr) => {
|
||||
assert_eq!(
|
||||
pns($lhs).and_then(|(f, _)| f.translate()),
|
||||
pns($lhs).and_then(|(f, _)| f.translate().ok()),
|
||||
$rhs.map(<String as From<&str>>::from)
|
||||
)
|
||||
};
|
||||
@ -37,7 +37,7 @@ macro_rules! assert_pns_eq_sub {
|
||||
fn test_iter() {
|
||||
use super::iter_subs;
|
||||
let s = "The $0'th word $$ is: `$WORD` $!\n";
|
||||
let subs: Vec<_> = iter_subs(s, 0).map(|sub| sub.translate()).collect();
|
||||
let subs: Vec<_> = iter_subs(s, 0).map(|sub| sub.translate().ok()).collect();
|
||||
assert_eq!(
|
||||
subs.iter().map(|ms| ms.as_ref().map(|s| &s[..])).collect::<Vec<_>>(),
|
||||
vec![Some("{0}"), None, Some("{WORD}")]
|
||||
|
@ -129,7 +129,8 @@ fn to_pass_builder_opt_level(cfg: config::OptLevel) -> llvm::PassBuilderOptLevel
|
||||
fn to_llvm_relocation_model(relocation_model: RelocModel) -> llvm::RelocModel {
|
||||
match relocation_model {
|
||||
RelocModel::Static => llvm::RelocModel::Static,
|
||||
RelocModel::Pic => llvm::RelocModel::PIC,
|
||||
// LLVM doesn't have a PIE relocation model, it represents PIE as PIC with an extra attribute.
|
||||
RelocModel::Pic | RelocModel::Pie => llvm::RelocModel::PIC,
|
||||
RelocModel::DynamicNoPic => llvm::RelocModel::DynamicNoPic,
|
||||
RelocModel::Ropi => llvm::RelocModel::ROPI,
|
||||
RelocModel::Rwpi => llvm::RelocModel::RWPI,
|
||||
|
@ -195,11 +195,14 @@ pub unsafe fn create_module(
|
||||
let llvm_target = SmallCStr::new(&sess.target.llvm_target);
|
||||
llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr());
|
||||
|
||||
if sess.relocation_model() == RelocModel::Pic {
|
||||
let reloc_model = sess.relocation_model();
|
||||
if matches!(reloc_model, RelocModel::Pic | RelocModel::Pie) {
|
||||
llvm::LLVMRustSetModulePICLevel(llmod);
|
||||
// PIE is potentially more effective than PIC, but can only be used in executables.
|
||||
// If all our outputs are executables, then we can relax PIC to PIE.
|
||||
if sess.crate_types().iter().all(|ty| *ty == CrateType::Executable) {
|
||||
if reloc_model == RelocModel::Pie
|
||||
|| sess.crate_types().iter().all(|ty| *ty == CrateType::Executable)
|
||||
{
|
||||
llvm::LLVMRustSetModulePIELevel(llmod);
|
||||
}
|
||||
}
|
||||
|
@ -211,9 +211,16 @@ fn print(&self, req: PrintRequest, sess: &Session) {
|
||||
match req {
|
||||
PrintRequest::RelocationModels => {
|
||||
println!("Available relocation models:");
|
||||
for name in
|
||||
&["static", "pic", "dynamic-no-pic", "ropi", "rwpi", "ropi-rwpi", "default"]
|
||||
{
|
||||
for name in &[
|
||||
"static",
|
||||
"pic",
|
||||
"pie",
|
||||
"dynamic-no-pic",
|
||||
"ropi",
|
||||
"rwpi",
|
||||
"ropi-rwpi",
|
||||
"default",
|
||||
] {
|
||||
println!(" {}", name);
|
||||
}
|
||||
println!();
|
||||
|
@ -143,6 +143,12 @@ pub(crate) unsafe fn should_assume_dso_local(
|
||||
return true;
|
||||
}
|
||||
|
||||
// With pie relocation model calls of functions defined in the translation
|
||||
// unit can use copy relocations.
|
||||
if self.tcx.sess.relocation_model() == RelocModel::Pie && !is_declaration {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1490,9 +1490,13 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fn link_output_kind(sess: &Session, crate_type: CrateType) -> LinkOutputKind {
|
||||
let kind = match (crate_type, sess.crt_static(Some(crate_type)), sess.relocation_model()) {
|
||||
(CrateType::Executable, _, _) if sess.is_wasi_reactor() => LinkOutputKind::WasiReactorExe,
|
||||
(CrateType::Executable, false, RelocModel::Pic) => LinkOutputKind::DynamicPicExe,
|
||||
(CrateType::Executable, false, RelocModel::Pic | RelocModel::Pie) => {
|
||||
LinkOutputKind::DynamicPicExe
|
||||
}
|
||||
(CrateType::Executable, false, _) => LinkOutputKind::DynamicNoPicExe,
|
||||
(CrateType::Executable, true, RelocModel::Pic) => LinkOutputKind::StaticPicExe,
|
||||
(CrateType::Executable, true, RelocModel::Pic | RelocModel::Pie) => {
|
||||
LinkOutputKind::StaticPicExe
|
||||
}
|
||||
(CrateType::Executable, true, _) => LinkOutputKind::StaticNoPicExe,
|
||||
(_, true, _) => LinkOutputKind::StaticDylib,
|
||||
(_, false, _) => LinkOutputKind::DynamicDylib,
|
||||
|
@ -384,6 +384,16 @@ pub fn has_type_params(&self) -> bool {
|
||||
self.args.iter().any(|arg| matches!(arg, GenericArg::Type(_)))
|
||||
}
|
||||
|
||||
pub fn has_err(&self) -> bool {
|
||||
self.args.iter().any(|arg| match arg {
|
||||
GenericArg::Type(ty) => matches!(ty.kind, TyKind::Err),
|
||||
_ => false,
|
||||
}) || self.bindings.iter().any(|arg| match arg.kind {
|
||||
TypeBindingKind::Equality { ty } => matches!(ty.kind, TyKind::Err),
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn num_type_params(&self) -> usize {
|
||||
self.args.iter().filter(|arg| matches!(arg, GenericArg::Type(_))).count()
|
||||
|
@ -32,3 +32,5 @@ chalk-ir = "0.55.0"
|
||||
smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
rustc_type_ir = { path = "../rustc_type_ir" }
|
||||
rand = "0.8.4"
|
||||
rand_xoshiro = "0.6.0"
|
||||
|
@ -24,6 +24,9 @@
|
||||
use std::num::NonZeroUsize;
|
||||
use std::ops::Bound;
|
||||
|
||||
use rand::{seq::SliceRandom, SeedableRng};
|
||||
use rand_xoshiro::Xoshiro128StarStar;
|
||||
|
||||
pub fn provide(providers: &mut ty::query::Providers) {
|
||||
*providers =
|
||||
ty::query::Providers { layout_of, fn_abi_of_fn_ptr, fn_abi_of_instance, ..*providers };
|
||||
@ -324,6 +327,10 @@ fn univariant_uninterned(
|
||||
|
||||
let mut inverse_memory_index: Vec<u32> = (0..fields.len() as u32).collect();
|
||||
|
||||
// `ReprOptions.layout_seed` is a deterministic seed that we can use to
|
||||
// randomize field ordering with
|
||||
let mut rng = Xoshiro128StarStar::seed_from_u64(repr.field_shuffle_seed);
|
||||
|
||||
let optimize = !repr.inhibit_struct_field_reordering_opt();
|
||||
if optimize {
|
||||
let end =
|
||||
@ -332,20 +339,35 @@ fn univariant_uninterned(
|
||||
let field_align = |f: &TyAndLayout<'_>| {
|
||||
if let Some(pack) = pack { f.align.abi.min(pack) } else { f.align.abi }
|
||||
};
|
||||
match kind {
|
||||
StructKind::AlwaysSized | StructKind::MaybeUnsized => {
|
||||
optimizing.sort_by_key(|&x| {
|
||||
// Place ZSTs first to avoid "interesting offsets",
|
||||
// especially with only one or two non-ZST fields.
|
||||
let f = &fields[x as usize];
|
||||
(!f.is_zst(), cmp::Reverse(field_align(f)))
|
||||
});
|
||||
}
|
||||
StructKind::Prefixed(..) => {
|
||||
// Sort in ascending alignment so that the layout stay optimal
|
||||
// regardless of the prefix
|
||||
optimizing.sort_by_key(|&x| field_align(&fields[x as usize]));
|
||||
|
||||
// If `-Z randomize-layout` was enabled for the type definition we can shuffle
|
||||
// the field ordering to try and catch some code making assumptions about layouts
|
||||
// we don't guarantee
|
||||
if repr.can_randomize_type_layout() {
|
||||
// Shuffle the ordering of the fields
|
||||
optimizing.shuffle(&mut rng);
|
||||
|
||||
// Otherwise we just leave things alone and actually optimize the type's fields
|
||||
} else {
|
||||
match kind {
|
||||
StructKind::AlwaysSized | StructKind::MaybeUnsized => {
|
||||
optimizing.sort_by_key(|&x| {
|
||||
// Place ZSTs first to avoid "interesting offsets",
|
||||
// especially with only one or two non-ZST fields.
|
||||
let f = &fields[x as usize];
|
||||
(!f.is_zst(), cmp::Reverse(field_align(f)))
|
||||
});
|
||||
}
|
||||
|
||||
StructKind::Prefixed(..) => {
|
||||
// Sort in ascending alignment so that the layout stays optimal
|
||||
// regardless of the prefix
|
||||
optimizing.sort_by_key(|&x| field_align(&fields[x as usize]));
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(Kixiron): We can always shuffle fields within a given alignment class
|
||||
// regardless of the status of `-Z randomize-layout`
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1491,6 +1491,9 @@ pub struct ReprFlags: u8 {
|
||||
const IS_LINEAR = 1 << 3;
|
||||
// If true, don't expose any niche to type's context.
|
||||
const HIDE_NICHE = 1 << 4;
|
||||
// If true, the type's layout can be randomized using
|
||||
// the seed stored in `ReprOptions.layout_seed`
|
||||
const RANDOMIZE_LAYOUT = 1 << 5;
|
||||
// Any of these flags being set prevent field reordering optimisation.
|
||||
const IS_UNOPTIMISABLE = ReprFlags::IS_C.bits |
|
||||
ReprFlags::IS_SIMD.bits |
|
||||
@ -1505,6 +1508,14 @@ pub struct ReprOptions {
|
||||
pub align: Option<Align>,
|
||||
pub pack: Option<Align>,
|
||||
pub flags: ReprFlags,
|
||||
/// The seed to be used for randomizing a type's layout
|
||||
///
|
||||
/// Note: This could technically be a `[u8; 16]` (a `u128`) which would
|
||||
/// be the "most accurate" hash as it'd encompass the item and crate
|
||||
/// hash without loss, but it does pay the price of being larger.
|
||||
/// Everything's a tradeoff, a `u64` seed should be sufficient for our
|
||||
/// purposes (primarily `-Z randomize-layout`)
|
||||
pub field_shuffle_seed: u64,
|
||||
}
|
||||
|
||||
impl ReprOptions {
|
||||
@ -1513,6 +1524,11 @@ pub fn new(tcx: TyCtxt<'_>, did: DefId) -> ReprOptions {
|
||||
let mut size = None;
|
||||
let mut max_align: Option<Align> = None;
|
||||
let mut min_pack: Option<Align> = None;
|
||||
|
||||
// Generate a deterministically-derived seed from the item's path hash
|
||||
// to allow for cross-crate compilation to actually work
|
||||
let field_shuffle_seed = tcx.def_path_hash(did).0.to_smaller_hash();
|
||||
|
||||
for attr in tcx.get_attrs(did).iter() {
|
||||
for r in attr::find_repr_attrs(&tcx.sess, attr) {
|
||||
flags.insert(match r {
|
||||
@ -1541,33 +1557,45 @@ pub fn new(tcx: TyCtxt<'_>, did: DefId) -> ReprOptions {
|
||||
}
|
||||
}
|
||||
|
||||
// If `-Z randomize-layout` was enabled for the type definition then we can
|
||||
// consider performing layout randomization
|
||||
if tcx.sess.opts.debugging_opts.randomize_layout {
|
||||
flags.insert(ReprFlags::RANDOMIZE_LAYOUT);
|
||||
}
|
||||
|
||||
// This is here instead of layout because the choice must make it into metadata.
|
||||
if !tcx.consider_optimizing(|| format!("Reorder fields of {:?}", tcx.def_path_str(did))) {
|
||||
flags.insert(ReprFlags::IS_LINEAR);
|
||||
}
|
||||
ReprOptions { int: size, align: max_align, pack: min_pack, flags }
|
||||
|
||||
Self { int: size, align: max_align, pack: min_pack, flags, field_shuffle_seed }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn simd(&self) -> bool {
|
||||
self.flags.contains(ReprFlags::IS_SIMD)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn c(&self) -> bool {
|
||||
self.flags.contains(ReprFlags::IS_C)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn packed(&self) -> bool {
|
||||
self.pack.is_some()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn transparent(&self) -> bool {
|
||||
self.flags.contains(ReprFlags::IS_TRANSPARENT)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn linear(&self) -> bool {
|
||||
self.flags.contains(ReprFlags::IS_LINEAR)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn hide_niche(&self) -> bool {
|
||||
self.flags.contains(ReprFlags::HIDE_NICHE)
|
||||
@ -1594,9 +1622,17 @@ pub fn inhibit_struct_field_reordering_opt(&self) -> bool {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
self.flags.intersects(ReprFlags::IS_UNOPTIMISABLE) || self.int.is_some()
|
||||
}
|
||||
|
||||
/// Returns `true` if this type is valid for reordering and `-Z randomize-layout`
|
||||
/// was enabled for its declaration crate
|
||||
pub fn can_randomize_type_layout(&self) -> bool {
|
||||
!self.inhibit_struct_field_reordering_opt()
|
||||
&& self.flags.contains(ReprFlags::RANDOMIZE_LAYOUT)
|
||||
}
|
||||
|
||||
/// Returns `true` if this `#[repr()]` should inhibit union ABI optimisations.
|
||||
pub fn inhibit_union_abi_opt(&self) -> bool {
|
||||
self.c()
|
||||
|
@ -147,7 +147,7 @@ fn try_inlining(
|
||||
self.check_mir_body(callsite, callee_body, callee_attrs)?;
|
||||
|
||||
if !self.tcx.consider_optimizing(|| {
|
||||
format!("Inline {:?} into {}", callee_body.span, callsite.callee)
|
||||
format!("Inline {:?} into {:?}", callsite.callee, caller_body.source)
|
||||
}) {
|
||||
return Err("optimization fuel exhausted");
|
||||
}
|
||||
|
@ -495,20 +495,28 @@ fn parse_assoc_equality_term(&mut self, ident: Ident, eq: Span) -> PResult<'a, P
|
||||
None => {
|
||||
let after_eq = eq.shrink_to_hi();
|
||||
let before_next = self.token.span.shrink_to_lo();
|
||||
self.struct_span_err(after_eq.to(before_next), "missing type to the right of `=`")
|
||||
.span_suggestion(
|
||||
let mut err = self
|
||||
.struct_span_err(after_eq.to(before_next), "missing type to the right of `=`");
|
||||
if matches!(self.token.kind, token::Comma | token::Gt) {
|
||||
err.span_suggestion(
|
||||
self.sess.source_map().next_point(eq).to(before_next),
|
||||
"to constrain the associated type, add a type after `=`",
|
||||
" TheType".to_string(),
|
||||
Applicability::HasPlaceholders,
|
||||
)
|
||||
.span_suggestion(
|
||||
);
|
||||
err.span_suggestion(
|
||||
eq.to(before_next),
|
||||
&format!("remove the `=` if `{}` is a type", ident),
|
||||
String::new(),
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
.emit();
|
||||
} else {
|
||||
err.span_label(
|
||||
self.token.span,
|
||||
&format!("expected type, found {}", super::token_descr(&self.token)),
|
||||
)
|
||||
};
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
Ok(self.mk_ty(span, ast::TyKind::Err))
|
||||
@ -572,6 +580,25 @@ pub(super) fn parse_generic_arg(&mut self) -> PResult<'a, Option<GenericArg>> {
|
||||
return self.recover_const_arg(start, err).map(Some);
|
||||
}
|
||||
}
|
||||
} else if self.eat_keyword_noexpect(kw::Const) {
|
||||
// Detect and recover from the old, pre-RFC2000 syntax for const generics.
|
||||
let mut err = self.struct_span_err(
|
||||
start,
|
||||
"expected lifetime, type, or constant, found keyword `const`",
|
||||
);
|
||||
if self.check_const_arg() {
|
||||
err.span_suggestion_verbose(
|
||||
start.until(self.token.span),
|
||||
"the `const` keyword is only needed in the definition of the type",
|
||||
String::new(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
err.emit();
|
||||
GenericArg::Const(self.parse_const_arg()?)
|
||||
} else {
|
||||
let after_kw_const = self.token.span;
|
||||
return self.recover_const_arg(after_kw_const, err).map(Some);
|
||||
}
|
||||
} else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
@ -1246,6 +1246,8 @@ mod parse {
|
||||
"enable queries of the dependency graph for regression testing (default: no)"),
|
||||
query_stats: bool = (false, parse_bool, [UNTRACKED],
|
||||
"print some statistics about the query system (default: no)"),
|
||||
randomize_layout: bool = (false, parse_bool, [TRACKED],
|
||||
"randomize the layout of types (default: no)"),
|
||||
relax_elf_relocations: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||
"whether ELF relocations can be relaxed"),
|
||||
relro_level: Option<RelroLevel> = (None, parse_relro_level, [TRACKED],
|
||||
|
@ -162,9 +162,6 @@ pub struct Session {
|
||||
/// Data about code being compiled, gathered during compilation.
|
||||
pub code_stats: CodeStats,
|
||||
|
||||
/// If `-zfuel=crate=n` is specified, `Some(crate)`.
|
||||
optimization_fuel_crate: Option<String>,
|
||||
|
||||
/// Tracks fuel info if `-zfuel=crate=n` is specified.
|
||||
optimization_fuel: Lock<OptimizationFuel>,
|
||||
|
||||
@ -882,7 +879,7 @@ pub fn print_perf_stats(&self) {
|
||||
/// This expends fuel if applicable, and records fuel if applicable.
|
||||
pub fn consider_optimizing<T: Fn() -> String>(&self, crate_name: &str, msg: T) -> bool {
|
||||
let mut ret = true;
|
||||
if let Some(ref c) = self.optimization_fuel_crate {
|
||||
if let Some((ref c, _)) = self.opts.debugging_opts.fuel {
|
||||
if c == crate_name {
|
||||
assert_eq!(self.threads(), 1);
|
||||
let mut fuel = self.optimization_fuel.lock();
|
||||
@ -1260,7 +1257,6 @@ pub fn build_session(
|
||||
let local_crate_source_file =
|
||||
local_crate_source_file.map(|path| file_path_mapping.map_prefix(path).0);
|
||||
|
||||
let optimization_fuel_crate = sopts.debugging_opts.fuel.as_ref().map(|i| i.0.clone());
|
||||
let optimization_fuel = Lock::new(OptimizationFuel {
|
||||
remaining: sopts.debugging_opts.fuel.as_ref().map_or(0, |i| i.1),
|
||||
out_of_fuel: false,
|
||||
@ -1311,7 +1307,6 @@ pub fn build_session(
|
||||
normalize_projection_ty: AtomicUsize::new(0),
|
||||
},
|
||||
code_stats: Default::default(),
|
||||
optimization_fuel_crate,
|
||||
optimization_fuel,
|
||||
print_fuel,
|
||||
jobserver: jobserver::client(),
|
||||
|
@ -288,6 +288,7 @@ fn to_json(&self) -> Json {
|
||||
pub enum RelocModel {
|
||||
Static,
|
||||
Pic,
|
||||
Pie,
|
||||
DynamicNoPic,
|
||||
Ropi,
|
||||
Rwpi,
|
||||
@ -301,6 +302,7 @@ fn from_str(s: &str) -> Result<RelocModel, ()> {
|
||||
Ok(match s {
|
||||
"static" => RelocModel::Static,
|
||||
"pic" => RelocModel::Pic,
|
||||
"pie" => RelocModel::Pie,
|
||||
"dynamic-no-pic" => RelocModel::DynamicNoPic,
|
||||
"ropi" => RelocModel::Ropi,
|
||||
"rwpi" => RelocModel::Rwpi,
|
||||
@ -315,6 +317,7 @@ fn to_json(&self) -> Json {
|
||||
match *self {
|
||||
RelocModel::Static => "static",
|
||||
RelocModel::Pic => "pic",
|
||||
RelocModel::Pie => "pie",
|
||||
RelocModel::DynamicNoPic => "dynamic-no-pic",
|
||||
RelocModel::Ropi => "ropi",
|
||||
RelocModel::Rwpi => "rwpi",
|
||||
|
@ -600,7 +600,7 @@ pub(crate) fn check_generic_arg_count(
|
||||
def_id,
|
||||
)
|
||||
.diagnostic()
|
||||
.emit();
|
||||
.emit_unless(gen_args.has_err());
|
||||
|
||||
false
|
||||
};
|
||||
|
@ -435,6 +435,10 @@ Equivalent to the "uppercase" `-fPIC` or `-fPIE` options in other compilers,
|
||||
depending on the produced crate types. \
|
||||
This is the default model for majority of supported targets.
|
||||
|
||||
- `pie` - position independent executable, relocatable code but without support for symbol
|
||||
interpositioning (replacing symbols by name using `LD_PRELOAD` and similar). Equivalent to the "uppercase" `-fPIE` option in other compilers. `pie`
|
||||
code cannot be linked into shared libraries (you'll get a linking error on attempt to do this).
|
||||
|
||||
#### Special relocation models
|
||||
|
||||
- `dynamic-no-pic` - relocatable external references, non-relocatable code. \
|
||||
|
35
src/test/assembly/pic-relocation-model.rs
Normal file
35
src/test/assembly/pic-relocation-model.rs
Normal file
@ -0,0 +1,35 @@
|
||||
// revisions: x64
|
||||
// assembly-output: emit-asm
|
||||
// [x64] compile-flags: --target x86_64-unknown-linux-gnu -Crelocation-model=pic
|
||||
// [x64] needs-llvm-components: x86
|
||||
|
||||
|
||||
#![feature(no_core, lang_items)]
|
||||
#![no_core]
|
||||
#![crate_type="rlib"]
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
#[lang = "copy"]
|
||||
trait Copy {}
|
||||
|
||||
// CHECK-LABEL: call_other_fn:
|
||||
// CHECK: {{(jmpq|callq)}} *other_fn@GOTPCREL(%rip)
|
||||
#[no_mangle]
|
||||
pub fn call_other_fn() -> u8 {
|
||||
unsafe {
|
||||
other_fn()
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK-LABEL: other_fn:
|
||||
// CHECK: callq *foreign_fn@GOTPCREL(%rip)
|
||||
#[no_mangle]
|
||||
#[inline(never)]
|
||||
pub fn other_fn() -> u8 {
|
||||
unsafe {
|
||||
foreign_fn()
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {fn foreign_fn() -> u8;}
|
38
src/test/assembly/pie-relocation-model.rs
Normal file
38
src/test/assembly/pie-relocation-model.rs
Normal file
@ -0,0 +1,38 @@
|
||||
// revisions: x64
|
||||
// assembly-output: emit-asm
|
||||
// [x64] compile-flags: --target x86_64-unknown-linux-gnu -Crelocation-model=pie
|
||||
// [x64] needs-llvm-components: x86
|
||||
|
||||
|
||||
#![feature(no_core, lang_items)]
|
||||
#![no_core]
|
||||
#![crate_type="rlib"]
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
#[lang = "copy"]
|
||||
trait Copy {}
|
||||
|
||||
// CHECK-LABEL: call_other_fn:
|
||||
// With PIE local functions are called "directly".
|
||||
// CHECK: {{(jmp|callq)}} other_fn
|
||||
#[no_mangle]
|
||||
pub fn call_other_fn() -> u8 {
|
||||
unsafe {
|
||||
other_fn()
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK-LABEL: other_fn:
|
||||
// External functions are still called through GOT, since we don't know if the symbol
|
||||
// is defined in the binary or in the shared library.
|
||||
// CHECK: callq *foreign_fn@GOTPCREL(%rip)
|
||||
#[no_mangle]
|
||||
#[inline(never)]
|
||||
pub fn other_fn() -> u8 {
|
||||
unsafe {
|
||||
foreign_fn()
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {fn foreign_fn() -> u8;}
|
16
src/test/codegen/pic-relocation-model.rs
Normal file
16
src/test/codegen/pic-relocation-model.rs
Normal file
@ -0,0 +1,16 @@
|
||||
// compile-flags: -C relocation-model=pic
|
||||
|
||||
#![crate_type = "rlib"]
|
||||
|
||||
// CHECK: define i8 @call_foreign_fn()
|
||||
#[no_mangle]
|
||||
pub fn call_foreign_fn() -> u8 {
|
||||
unsafe {
|
||||
foreign_fn()
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK: declare zeroext i8 @foreign_fn()
|
||||
extern "C" {fn foreign_fn() -> u8;}
|
||||
|
||||
// CHECK: !{i32 7, !"PIC Level", i32 2}
|
22
src/test/codegen/pie-relocation-model.rs
Normal file
22
src/test/codegen/pie-relocation-model.rs
Normal file
@ -0,0 +1,22 @@
|
||||
// compile-flags: -C relocation-model=pie
|
||||
// only-x86_64-unknown-linux-gnu
|
||||
|
||||
#![crate_type = "rlib"]
|
||||
|
||||
// With PIE we know local functions cannot be interpositioned, we can mark them
|
||||
// as dso_local.
|
||||
// CHECK: define dso_local i8 @call_foreign_fn()
|
||||
#[no_mangle]
|
||||
pub fn call_foreign_fn() -> u8 {
|
||||
unsafe {
|
||||
foreign_fn()
|
||||
}
|
||||
}
|
||||
|
||||
// External functions are still marked as non-dso_local, since we don't know if the symbol
|
||||
// is defined in the binary or in the shared library.
|
||||
// CHECK: declare zeroext i8 @foreign_fn()
|
||||
extern "C" {fn foreign_fn() -> u8;}
|
||||
|
||||
// CHECK: !{i32 7, !"PIC Level", i32 2}
|
||||
// CHECK: !{i32 7, !"PIE Level", i32 2}
|
@ -0,0 +1,16 @@
|
||||
trait Foo<const N: usize> {
|
||||
fn do_x(&self) -> [u8; N];
|
||||
}
|
||||
|
||||
struct Bar;
|
||||
|
||||
const T: usize = 42;
|
||||
|
||||
impl Foo<const 3> for Bar {
|
||||
//~^ERROR expected lifetime, type, or constant, found keyword `const`
|
||||
fn do_x(&self) -> [u8; 3] {
|
||||
[0u8; 3]
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,14 @@
|
||||
error: expected lifetime, type, or constant, found keyword `const`
|
||||
--> $DIR/issue-89013-no-assoc.rs:9:10
|
||||
|
|
||||
LL | impl Foo<const 3> for Bar {
|
||||
| ^^^^^
|
||||
|
|
||||
help: the `const` keyword is only needed in the definition of the type
|
||||
|
|
||||
LL - impl Foo<const 3> for Bar {
|
||||
LL + impl Foo<3> for Bar {
|
||||
|
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -0,0 +1,17 @@
|
||||
trait Foo<const N: usize> {
|
||||
fn do_x(&self) -> [u8; N];
|
||||
}
|
||||
|
||||
struct Bar;
|
||||
|
||||
const T: usize = 42;
|
||||
|
||||
impl Foo<N = 3> for Bar {
|
||||
//~^ ERROR cannot constrain an associated constant to a value
|
||||
//~| ERROR associated type bindings are not allowed here
|
||||
fn do_x(&self) -> [u8; 3] {
|
||||
[0u8; 3]
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,18 @@
|
||||
error: cannot constrain an associated constant to a value
|
||||
--> $DIR/issue-89013-no-kw.rs:9:10
|
||||
|
|
||||
LL | impl Foo<N = 3> for Bar {
|
||||
| -^^^-
|
||||
| | |
|
||||
| | ...cannot be constrained to this value
|
||||
| this associated constant...
|
||||
|
||||
error[E0229]: associated type bindings are not allowed here
|
||||
--> $DIR/issue-89013-no-kw.rs:9:10
|
||||
|
|
||||
LL | impl Foo<N = 3> for Bar {
|
||||
| ^^^^^ associated type not allowed here
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0229`.
|
@ -0,0 +1,16 @@
|
||||
trait Foo<const N: usize> {
|
||||
fn do_x(&self) -> [u8; N];
|
||||
}
|
||||
|
||||
struct Bar;
|
||||
|
||||
const T: usize = 42;
|
||||
|
||||
impl Foo<N = type 3> for Bar {
|
||||
//~^ERROR missing type to the right of `=`
|
||||
fn do_x(&self) -> [u8; 3] {
|
||||
[0u8; 3]
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,8 @@
|
||||
error: missing type to the right of `=`
|
||||
--> $DIR/issue-89013-type.rs:9:13
|
||||
|
|
||||
LL | impl Foo<N = type 3> for Bar {
|
||||
| ^---- expected type, found keyword `type`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -0,0 +1,18 @@
|
||||
trait Foo<const N: usize> {
|
||||
fn do_x(&self) -> [u8; N];
|
||||
}
|
||||
|
||||
struct Bar;
|
||||
|
||||
const T: usize = 42;
|
||||
|
||||
impl Foo<N = const 3> for Bar {
|
||||
//~^ ERROR expected lifetime, type, or constant, found keyword `const`
|
||||
//~| ERROR cannot constrain an associated constant to a value
|
||||
//~| ERROR associated type bindings are not allowed here
|
||||
fn do_x(&self) -> [u8; 3] {
|
||||
[0u8; 3]
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,30 @@
|
||||
error: expected lifetime, type, or constant, found keyword `const`
|
||||
--> $DIR/issue-89013.rs:9:14
|
||||
|
|
||||
LL | impl Foo<N = const 3> for Bar {
|
||||
| ^^^^^
|
||||
|
|
||||
help: the `const` keyword is only needed in the definition of the type
|
||||
|
|
||||
LL - impl Foo<N = const 3> for Bar {
|
||||
LL + impl Foo<N = 3> for Bar {
|
||||
|
|
||||
|
||||
error: cannot constrain an associated constant to a value
|
||||
--> $DIR/issue-89013.rs:9:10
|
||||
|
|
||||
LL | impl Foo<N = const 3> for Bar {
|
||||
| -^^^^^^^^^-
|
||||
| | |
|
||||
| | ...cannot be constrained to this value
|
||||
| this associated constant...
|
||||
|
||||
error[E0229]: associated type bindings are not allowed here
|
||||
--> $DIR/issue-89013.rs:9:10
|
||||
|
|
||||
LL | impl Foo<N = const 3> for Bar {
|
||||
| ^^^^^^^^^^^ associated type not allowed here
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0229`.
|
14
src/test/ui/fmt/issue-89173.rs
Normal file
14
src/test/ui/fmt/issue-89173.rs
Normal file
@ -0,0 +1,14 @@
|
||||
// Regression test for #89173: Make sure a helpful note is issued for
|
||||
// printf-style format strings using `*` to specify the width.
|
||||
|
||||
fn main() {
|
||||
let num = 0x0abcde;
|
||||
let width = 6;
|
||||
print!("%0*x", width, num);
|
||||
//~^ ERROR: multiple unused formatting arguments
|
||||
//~| NOTE: multiple missing formatting specifiers
|
||||
//~| NOTE: argument never used
|
||||
//~| NOTE: argument never used
|
||||
//~| NOTE: format specifiers use curly braces, and you have to use a positional or named parameter for the width
|
||||
//~| NOTE: printf formatting not supported
|
||||
}
|
18
src/test/ui/fmt/issue-89173.stderr
Normal file
18
src/test/ui/fmt/issue-89173.stderr
Normal file
@ -0,0 +1,18 @@
|
||||
error: multiple unused formatting arguments
|
||||
--> $DIR/issue-89173.rs:7:20
|
||||
|
|
||||
LL | print!("%0*x", width, num);
|
||||
| ------ ^^^^^ ^^^ argument never used
|
||||
| | |
|
||||
| | argument never used
|
||||
| multiple missing formatting specifiers
|
||||
|
|
||||
note: format specifiers use curly braces, and you have to use a positional or named parameter for the width
|
||||
--> $DIR/issue-89173.rs:7:13
|
||||
|
|
||||
LL | print!("%0*x", width, num);
|
||||
| ^^^^
|
||||
= note: printf formatting not supported; see the documentation for `std::fmt`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -167,6 +167,7 @@
|
||||
"rand_hc",
|
||||
"rand_pcg",
|
||||
"rand_xorshift",
|
||||
"rand_xoshiro",
|
||||
"redox_syscall",
|
||||
"regex",
|
||||
"regex-automata",
|
||||
|
Loading…
Reference in New Issue
Block a user