Skip to content

Commit d3edfd1

Browse files
committed
Auto merge of rust-lang#111001 - matthiaskrgr:rollup-u590scu, r=matthiaskrgr
Rollup of 7 pull requests Successful merges: - rust-lang#110586 (Fix Unreadable non-UTF-8 output on localized MSVC) - rust-lang#110652 (Add test for warning-free builds of `core` under `no_global_oom_handling`) - rust-lang#110973 (improve error notes for packed struct reference diagnostic) - rust-lang#110981 (Move most rustdoc-ui tests into subdirectories) - rust-lang#110983 (rustdoc: Get `repr` information through `AdtDef` for foreign items) - rust-lang#110984 (Do not resolve anonymous lifetimes in consts to be static.) - rust-lang#110997 (Improve internal field comments on `slice::Iter(Mut)`) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
2 parents f5adff6 + f720813 commit d3edfd1

File tree

223 files changed

+375
-119
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

223 files changed

+375
-119
lines changed

Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -3250,6 +3250,7 @@ dependencies = [
32503250
"tempfile",
32513251
"thorin-dwp",
32523252
"tracing",
3253+
"windows 0.46.0",
32533254
]
32543255

32553256
[[package]]

compiler/rustc_codegen_ssa/Cargo.toml

+4
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,7 @@ libc = "0.2.50"
4949
version = "0.30.1"
5050
default-features = false
5151
features = ["read_core", "elf", "macho", "pe", "unaligned", "archive", "write"]
52+
53+
[target.'cfg(windows)'.dependencies.windows]
54+
version = "0.46.0"
55+
features = ["Win32_Globalization"]

compiler/rustc_codegen_ssa/src/back/link.rs

+78-1
Original file line numberDiff line numberDiff line change
@@ -860,7 +860,7 @@ fn link_natively<'a>(
860860
if !prog.status.success() {
861861
let mut output = prog.stderr.clone();
862862
output.extend_from_slice(&prog.stdout);
863-
let escaped_output = escape_string(&output);
863+
let escaped_output = escape_linker_output(&output, flavor);
864864
// FIXME: Add UI tests for this error.
865865
let err = errors::LinkingFailed {
866866
linker_path: &linker_path,
@@ -1052,6 +1052,83 @@ fn escape_string(s: &[u8]) -> String {
10521052
}
10531053
}
10541054

1055+
#[cfg(not(windows))]
1056+
fn escape_linker_output(s: &[u8], _flavour: LinkerFlavor) -> String {
1057+
escape_string(s)
1058+
}
1059+
1060+
/// If the output of the msvc linker is not UTF-8 and the host is Windows,
1061+
/// then try to convert the string from the OEM encoding.
1062+
#[cfg(windows)]
1063+
fn escape_linker_output(s: &[u8], flavour: LinkerFlavor) -> String {
1064+
// This only applies to the actual MSVC linker.
1065+
if flavour != LinkerFlavor::Msvc(Lld::No) {
1066+
return escape_string(s);
1067+
}
1068+
match str::from_utf8(s) {
1069+
Ok(s) => return s.to_owned(),
1070+
Err(_) => match win::locale_byte_str_to_string(s, win::oem_code_page()) {
1071+
Some(s) => s,
1072+
// The string is not UTF-8 and isn't valid for the OEM code page
1073+
None => format!("Non-UTF-8 output: {}", s.escape_ascii()),
1074+
},
1075+
}
1076+
}
1077+
1078+
/// Wrappers around the Windows API.
1079+
#[cfg(windows)]
1080+
mod win {
1081+
use windows::Win32::Globalization::{
1082+
GetLocaleInfoEx, MultiByteToWideChar, CP_OEMCP, LOCALE_IUSEUTF8LEGACYOEMCP,
1083+
LOCALE_NAME_SYSTEM_DEFAULT, LOCALE_RETURN_NUMBER, MB_ERR_INVALID_CHARS,
1084+
};
1085+
1086+
/// Get the Windows system OEM code page. This is most notably the code page
1087+
/// used for link.exe's output.
1088+
pub fn oem_code_page() -> u32 {
1089+
unsafe {
1090+
let mut cp: u32 = 0;
1091+
// We're using the `LOCALE_RETURN_NUMBER` flag to return a u32.
1092+
// But the API requires us to pass the data as though it's a [u16] string.
1093+
let len = std::mem::size_of::<u32>() / std::mem::size_of::<u16>();
1094+
let data = std::slice::from_raw_parts_mut(&mut cp as *mut u32 as *mut u16, len);
1095+
let len_written = GetLocaleInfoEx(
1096+
LOCALE_NAME_SYSTEM_DEFAULT,
1097+
LOCALE_IUSEUTF8LEGACYOEMCP | LOCALE_RETURN_NUMBER,
1098+
Some(data),
1099+
);
1100+
if len_written as usize == len { cp } else { CP_OEMCP }
1101+
}
1102+
}
1103+
/// Try to convert a multi-byte string to a UTF-8 string using the given code page
1104+
/// The string does not need to be null terminated.
1105+
///
1106+
/// This is implemented as a wrapper around `MultiByteToWideChar`.
1107+
/// See <https://learn.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-multibytetowidechar>
1108+
///
1109+
/// It will fail if the multi-byte string is longer than `i32::MAX` or if it contains
1110+
/// any invalid bytes for the expected encoding.
1111+
pub fn locale_byte_str_to_string(s: &[u8], code_page: u32) -> Option<String> {
1112+
// `MultiByteToWideChar` requires a length to be a "positive integer".
1113+
if s.len() > isize::MAX as usize {
1114+
return None;
1115+
}
1116+
// Error if the string is not valid for the expected code page.
1117+
let flags = MB_ERR_INVALID_CHARS;
1118+
// Call MultiByteToWideChar twice.
1119+
// First to calculate the length then to convert the string.
1120+
let mut len = unsafe { MultiByteToWideChar(code_page, flags, s, None) };
1121+
if len > 0 {
1122+
let mut utf16 = vec![0; len as usize];
1123+
len = unsafe { MultiByteToWideChar(code_page, flags, s, Some(&mut utf16)) };
1124+
if len > 0 {
1125+
return utf16.get(..len as usize).map(String::from_utf16_lossy);
1126+
}
1127+
}
1128+
None
1129+
}
1130+
}
1131+
10551132
fn add_sanitizer_libraries(sess: &Session, crate_type: CrateType, linker: &mut dyn Linker) {
10561133
// On macOS the runtimes are distributed as dylibs which should be linked to
10571134
// both executables and dynamic shared objects. Everywhere else the runtimes

compiler/rustc_feature/src/builtin_attrs.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
344344
),
345345
ungated!(link_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
346346
ungated!(no_link, Normal, template!(Word), WarnFollowing),
347-
ungated!(repr, Normal, template!(List: "C"), DuplicatesOk),
347+
ungated!(repr, Normal, template!(List: "C"), DuplicatesOk, @only_local: true),
348348
ungated!(export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
349349
ungated!(link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
350350
ungated!(no_mangle, Normal, template!(Word), WarnFollowing, @only_local: true),

compiler/rustc_mir_transform/src/check_packed_ref.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,11 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> {
5656
"reference to packed field is unaligned"
5757
)
5858
.note(
59-
"fields of packed structs are not properly aligned, and creating \
60-
a misaligned reference is undefined behavior (even if that \
59+
"packed structs are only aligned by one byte, and many modern architectures \
60+
penalize unaligned field accesses"
61+
)
62+
.note(
63+
"creating a misaligned reference is undefined behavior (even if that \
6164
reference is never dereferenced)",
6265
).help(
6366
"copy the field contents to a local variable, or replace the \

compiler/rustc_resolve/src/late.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -656,7 +656,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
656656
fn visit_anon_const(&mut self, constant: &'ast AnonConst) {
657657
// We deal with repeat expressions explicitly in `resolve_expr`.
658658
self.with_lifetime_rib(LifetimeRibKind::AnonConst, |this| {
659-
this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| {
659+
this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
660660
this.resolve_anon_const(constant, IsRepeatExpr::No);
661661
})
662662
})
@@ -4126,7 +4126,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
41264126
ExprKind::Repeat(ref elem, ref ct) => {
41274127
self.visit_expr(elem);
41284128
self.with_lifetime_rib(LifetimeRibKind::AnonConst, |this| {
4129-
this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| {
4129+
this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
41304130
this.resolve_anon_const(ct, IsRepeatExpr::Yes)
41314131
})
41324132
});

library/core/src/slice/iter.rs

+20-6
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,17 @@ impl<'a, T> IntoIterator for &'a mut [T] {
6060
#[stable(feature = "rust1", since = "1.0.0")]
6161
#[must_use = "iterators are lazy and do nothing unless consumed"]
6262
pub struct Iter<'a, T: 'a> {
63+
/// The pointer to the next element to return, or the past-the-end location
64+
/// if the iterator is empty.
65+
///
66+
/// This address will be used for all ZST elements, never changed.
6367
ptr: NonNull<T>,
64-
end: *const T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that
65-
// ptr == end is a quick test for the Iterator being empty, that works
66-
// for both ZST and non-ZST.
68+
/// For non-ZSTs, the non-null pointer to the past-the-end element.
69+
///
70+
/// For ZSTs, this is `ptr.wrapping_byte_add(len)`.
71+
///
72+
/// For all types, `ptr == end` tests whether the iterator is empty.
73+
end: *const T,
6774
_marker: PhantomData<&'a T>,
6875
}
6976

@@ -179,10 +186,17 @@ impl<T> AsRef<[T]> for Iter<'_, T> {
179186
#[stable(feature = "rust1", since = "1.0.0")]
180187
#[must_use = "iterators are lazy and do nothing unless consumed"]
181188
pub struct IterMut<'a, T: 'a> {
189+
/// The pointer to the next element to return, or the past-the-end location
190+
/// if the iterator is empty.
191+
///
192+
/// This address will be used for all ZST elements, never changed.
182193
ptr: NonNull<T>,
183-
end: *mut T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that
184-
// ptr == end is a quick test for the Iterator being empty, that works
185-
// for both ZST and non-ZST.
194+
/// For non-ZSTs, the non-null pointer to the past-the-end element.
195+
///
196+
/// For ZSTs, this is `ptr.wrapping_byte_add(len)`.
197+
///
198+
/// For all types, `ptr == end` tests whether the iterator is empty.
199+
end: *mut T,
186200
_marker: PhantomData<&'a mut T>,
187201
}
188202

src/librustdoc/clean/types.rs

+73
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use arrayvec::ArrayVec;
1111
use thin_vec::ThinVec;
1212

1313
use rustc_ast as ast;
14+
use rustc_ast_pretty::pprust;
1415
use rustc_attr::{ConstStability, Deprecation, Stability, StabilityLevel};
1516
use rustc_const_eval::const_eval::is_unstable_const_fn;
1617
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -711,6 +712,78 @@ impl Item {
711712
};
712713
Some(tcx.visibility(def_id))
713714
}
715+
716+
pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, keep_as_is: bool) -> Vec<String> {
717+
const ALLOWED_ATTRIBUTES: &[Symbol] =
718+
&[sym::export_name, sym::link_section, sym::no_mangle, sym::repr, sym::non_exhaustive];
719+
720+
use rustc_abi::IntegerType;
721+
use rustc_middle::ty::ReprFlags;
722+
723+
let mut attrs: Vec<String> = self
724+
.attrs
725+
.other_attrs
726+
.iter()
727+
.filter_map(|attr| {
728+
if keep_as_is {
729+
Some(pprust::attribute_to_string(attr))
730+
} else if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) {
731+
Some(
732+
pprust::attribute_to_string(attr)
733+
.replace("\\\n", "")
734+
.replace('\n', "")
735+
.replace(" ", " "),
736+
)
737+
} else {
738+
None
739+
}
740+
})
741+
.collect();
742+
if let Some(def_id) = self.item_id.as_def_id() &&
743+
!def_id.is_local() &&
744+
// This check is needed because `adt_def` will panic if not a compatible type otherwise...
745+
matches!(self.type_(), ItemType::Struct | ItemType::Enum | ItemType::Union)
746+
{
747+
let repr = tcx.adt_def(def_id).repr();
748+
let mut out = Vec::new();
749+
if repr.flags.contains(ReprFlags::IS_C) {
750+
out.push("C");
751+
}
752+
if repr.flags.contains(ReprFlags::IS_TRANSPARENT) {
753+
out.push("transparent");
754+
}
755+
if repr.flags.contains(ReprFlags::IS_SIMD) {
756+
out.push("simd");
757+
}
758+
let pack_s;
759+
if let Some(pack) = repr.pack {
760+
pack_s = format!("packed({})", pack.bytes());
761+
out.push(&pack_s);
762+
}
763+
let align_s;
764+
if let Some(align) = repr.align {
765+
align_s = format!("align({})", align.bytes());
766+
out.push(&align_s);
767+
}
768+
let int_s;
769+
if let Some(int) = repr.int {
770+
int_s = match int {
771+
IntegerType::Pointer(is_signed) => {
772+
format!("{}size", if is_signed { 'i' } else { 'u' })
773+
}
774+
IntegerType::Fixed(size, is_signed) => {
775+
format!("{}{}", if is_signed { 'i' } else { 'u' }, size.size().bytes() * 8)
776+
}
777+
};
778+
out.push(&int_s);
779+
}
780+
if out.is_empty() {
781+
return Vec::new();
782+
}
783+
attrs.push(format!("#[repr({})]", out.join(", ")));
784+
}
785+
attrs
786+
}
714787
}
715788

716789
#[derive(Clone, Debug)]

src/librustdoc/html/render/mod.rs

+8-30
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ use std::str;
4848
use std::string::ToString;
4949

5050
use askama::Template;
51-
use rustc_ast_pretty::pprust;
5251
use rustc_attr::{ConstStability, Deprecation, StabilityLevel};
5352
use rustc_data_structures::captures::Captures;
5453
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -849,10 +848,10 @@ fn assoc_method(
849848
let (indent, indent_str, end_newline) = if parent == ItemType::Trait {
850849
header_len += 4;
851850
let indent_str = " ";
852-
write!(w, "{}", render_attributes_in_pre(meth, indent_str));
851+
write!(w, "{}", render_attributes_in_pre(meth, indent_str, tcx));
853852
(4, indent_str, Ending::NoNewline)
854853
} else {
855-
render_attributes_in_code(w, meth);
854+
render_attributes_in_code(w, meth, tcx);
856855
(0, "", Ending::Newline)
857856
};
858857
w.reserve(header_len + "<a href=\"\" class=\"fn\">{".len() + "</a>".len());
@@ -1021,36 +1020,15 @@ fn render_assoc_item(
10211020
}
10221021
}
10231022

1024-
const ALLOWED_ATTRIBUTES: &[Symbol] =
1025-
&[sym::export_name, sym::link_section, sym::no_mangle, sym::repr, sym::non_exhaustive];
1026-
1027-
fn attributes(it: &clean::Item) -> Vec<String> {
1028-
it.attrs
1029-
.other_attrs
1030-
.iter()
1031-
.filter_map(|attr| {
1032-
if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) {
1033-
Some(
1034-
pprust::attribute_to_string(attr)
1035-
.replace("\\\n", "")
1036-
.replace('\n', "")
1037-
.replace(" ", " "),
1038-
)
1039-
} else {
1040-
None
1041-
}
1042-
})
1043-
.collect()
1044-
}
1045-
10461023
// When an attribute is rendered inside a `<pre>` tag, it is formatted using
10471024
// a whitespace prefix and newline.
1048-
fn render_attributes_in_pre<'a>(
1025+
fn render_attributes_in_pre<'a, 'b: 'a>(
10491026
it: &'a clean::Item,
10501027
prefix: &'a str,
1051-
) -> impl fmt::Display + Captures<'a> {
1028+
tcx: TyCtxt<'b>,
1029+
) -> impl fmt::Display + Captures<'a> + Captures<'b> {
10521030
crate::html::format::display_fn(move |f| {
1053-
for a in attributes(it) {
1031+
for a in it.attributes(tcx, false) {
10541032
writeln!(f, "{}{}", prefix, a)?;
10551033
}
10561034
Ok(())
@@ -1059,8 +1037,8 @@ fn render_attributes_in_pre<'a>(
10591037

10601038
// When an attribute is rendered inside a <code> tag, it is formatted using
10611039
// a div to produce a newline after it.
1062-
fn render_attributes_in_code(w: &mut Buffer, it: &clean::Item) {
1063-
for a in attributes(it) {
1040+
fn render_attributes_in_code(w: &mut Buffer, it: &clean::Item, tcx: TyCtxt<'_>) {
1041+
for a in it.attributes(tcx, false) {
10641042
write!(w, "<div class=\"code-attribute\">{}</div>", a);
10651043
}
10661044
}

0 commit comments

Comments
 (0)