Skip to content

Commit 2b82e05

Browse files
Auto merge of #150900 - Urgau:rollup-og7uEW9, r=Urgau
Rollup of 9 pull requests Successful merges: - #149318 (Implement partial_sort_unstable for slice) - #150805 (Fix ICE in inline always warning emission.) - #150822 (Fix for ICE: eii: fn / macro rules None in find_attr()) - #150853 (std: sys: fs: uefi: Implement File::read) - #150855 (std: sys: fs: uefi: Implement File::tell) - #150881 (Fix std::fs::copy on WASI by setting proper OpenOptions flags) - #150891 (Fix a trivial typo in def_id.rs) - #150892 (Don't check `[mentions]` paths in submodules from tidy) - #150894 (cg_llvm: add a pause to make comment less confusing) r? @ghost
2 parents 1191620 + 2b8d078 commit 2b82e05

26 files changed

Lines changed: 702 additions & 129 deletions

File tree

compiler/rustc_ast/src/ast.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2117,10 +2117,9 @@ pub struct MacroDef {
21172117

21182118
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic, Walkable)]
21192119
pub struct EiiExternTarget {
2120-
/// path to the extern item we're targetting
2120+
/// path to the extern item we're targeting
21212121
pub extern_item_path: Path,
21222122
pub impl_unsafe: bool,
2123-
pub span: Span,
21242123
}
21252124

21262125
#[derive(Clone, Encodable, Decodable, Debug, Copy, Hash, Eq, PartialEq)]
@@ -3813,6 +3812,19 @@ pub struct Fn {
38133812
pub struct EiiImpl {
38143813
pub node_id: NodeId,
38153814
pub eii_macro_path: Path,
3815+
/// This field is an implementation detail that prevents a lot of bugs.
3816+
/// See <https://github.com/rust-lang/rust/issues/149981> for an example.
3817+
///
3818+
/// The problem is, that if we generate a declaration *together* with its default,
3819+
/// we generate both a declaration and an implementation. The generated implementation
3820+
/// uses the same mechanism to register itself as a user-defined implementation would,
3821+
/// despite being invisible to users. What does happen is a name resolution step.
3822+
/// The invisible default implementation has to find the declaration.
3823+
/// Both are generated at the same time, so we can skip that name resolution step.
3824+
///
3825+
/// This field is that shortcut: we prefill the extern target to skip a name resolution step,
3826+
/// making sure it never fails. It'd be awful UX if we fail name resolution in code invisible to the user.
3827+
pub known_eii_macro_resolution: Option<EiiExternTarget>,
38163828
pub impl_safety: Safety,
38173829
pub span: Span,
38183830
pub inner_span: Span,

compiler/rustc_ast_lowering/src/item.rs

Lines changed: 56 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use rustc_abi::ExternAbi;
22
use rustc_ast::visit::AssocCtxt;
33
use rustc_ast::*;
44
use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err};
5-
use rustc_hir::attrs::{AttributeKind, EiiDecl};
5+
use rustc_hir::attrs::{AttributeKind, EiiDecl, EiiImplResolution};
66
use rustc_hir::def::{DefKind, PerNS, Res};
77
use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
88
use rustc_hir::{
@@ -134,6 +134,56 @@ impl<'hir> LoweringContext<'_, 'hir> {
134134
}
135135
}
136136

137+
fn lower_eii_extern_target(
138+
&mut self,
139+
id: NodeId,
140+
eii_name: Ident,
141+
EiiExternTarget { extern_item_path, impl_unsafe }: &EiiExternTarget,
142+
) -> Option<EiiDecl> {
143+
self.lower_path_simple_eii(id, extern_item_path).map(|did| EiiDecl {
144+
eii_extern_target: did,
145+
impl_unsafe: *impl_unsafe,
146+
name: eii_name,
147+
})
148+
}
149+
150+
fn lower_eii_impl(
151+
&mut self,
152+
EiiImpl {
153+
node_id,
154+
eii_macro_path,
155+
impl_safety,
156+
span,
157+
inner_span,
158+
is_default,
159+
known_eii_macro_resolution,
160+
}: &EiiImpl,
161+
) -> hir::attrs::EiiImpl {
162+
let resolution = if let Some(target) = known_eii_macro_resolution
163+
&& let Some(decl) = self.lower_eii_extern_target(
164+
*node_id,
165+
// the expect is ok here since we always generate this path in the eii macro.
166+
eii_macro_path.segments.last().expect("at least one segment").ident,
167+
target,
168+
) {
169+
EiiImplResolution::Known(decl)
170+
} else if let Some(macro_did) = self.lower_path_simple_eii(*node_id, eii_macro_path) {
171+
EiiImplResolution::Macro(macro_did)
172+
} else {
173+
EiiImplResolution::Error(
174+
self.dcx().span_delayed_bug(*span, "eii never resolved without errors given"),
175+
)
176+
};
177+
178+
hir::attrs::EiiImpl {
179+
span: self.lower_span(*span),
180+
inner_span: self.lower_span(*inner_span),
181+
impl_marked_unsafe: self.lower_safety(*impl_safety, hir::Safety::Safe).is_unsafe(),
182+
is_default: *is_default,
183+
resolution,
184+
}
185+
}
186+
137187
fn generate_extra_attrs_for_item_kind(
138188
&mut self,
139189
id: NodeId,
@@ -143,49 +193,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
143193
ItemKind::Fn(box Fn { eii_impls, .. }) if eii_impls.is_empty() => Vec::new(),
144194
ItemKind::Fn(box Fn { eii_impls, .. }) => {
145195
vec![hir::Attribute::Parsed(AttributeKind::EiiImpls(
146-
eii_impls
147-
.iter()
148-
.flat_map(
149-
|EiiImpl {
150-
node_id,
151-
eii_macro_path,
152-
impl_safety,
153-
span,
154-
inner_span,
155-
is_default,
156-
}| {
157-
self.lower_path_simple_eii(*node_id, eii_macro_path).map(|did| {
158-
hir::attrs::EiiImpl {
159-
eii_macro: did,
160-
span: self.lower_span(*span),
161-
inner_span: self.lower_span(*inner_span),
162-
impl_marked_unsafe: self
163-
.lower_safety(*impl_safety, hir::Safety::Safe)
164-
.is_unsafe(),
165-
is_default: *is_default,
166-
}
167-
})
168-
},
169-
)
170-
.collect(),
196+
eii_impls.iter().map(|i| self.lower_eii_impl(i)).collect(),
171197
))]
172198
}
173-
ItemKind::MacroDef(
174-
_,
175-
MacroDef {
176-
eii_extern_target: Some(EiiExternTarget { extern_item_path, impl_unsafe, span }),
177-
..
178-
},
179-
) => self
180-
.lower_path_simple_eii(id, extern_item_path)
181-
.map(|did| {
182-
vec![hir::Attribute::Parsed(AttributeKind::EiiExternTarget(EiiDecl {
183-
eii_extern_target: did,
184-
impl_unsafe: *impl_unsafe,
185-
span: self.lower_span(*span),
186-
}))]
187-
})
199+
ItemKind::MacroDef(name, MacroDef { eii_extern_target: Some(target), .. }) => self
200+
.lower_eii_extern_target(id, *name, target)
201+
.map(|decl| vec![hir::Attribute::Parsed(AttributeKind::EiiExternTarget(decl))])
188202
.unwrap_or_default(),
203+
189204
ItemKind::ExternCrate(..)
190205
| ItemKind::Use(..)
191206
| ItemKind::Static(..)

compiler/rustc_builtin_macros/src/eii.rs

Lines changed: 73 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -103,19 +103,19 @@ fn eii_(
103103

104104
// span of the declaring item without attributes
105105
let item_span = func.sig.span;
106-
// span of the eii attribute and the item below it, i.e. the full declaration
107-
let decl_span = eii_attr_span.to(item_span);
108106
let foreign_item_name = func.ident;
109107

110108
let mut return_items = Vec::new();
111109

112110
if func.body.is_some() {
113111
return_items.push(Box::new(generate_default_impl(
112+
ecx,
114113
&func,
115114
impl_unsafe,
116115
macro_name,
117116
eii_attr_span,
118117
item_span,
118+
foreign_item_name,
119119
)))
120120
}
121121

@@ -133,7 +133,6 @@ fn eii_(
133133
macro_name,
134134
foreign_item_name,
135135
impl_unsafe,
136-
decl_span,
137136
)));
138137

139138
return_items.into_iter().map(wrap_item).collect()
@@ -187,11 +186,13 @@ fn filter_attrs_for_multiple_eii_attr(
187186
}
188187

189188
fn generate_default_impl(
189+
ecx: &mut ExtCtxt<'_>,
190190
func: &ast::Fn,
191191
impl_unsafe: bool,
192192
macro_name: Ident,
193193
eii_attr_span: Span,
194194
item_span: Span,
195+
foreign_item_name: Ident,
195196
) -> ast::Item {
196197
// FIXME: re-add some original attrs
197198
let attrs = ThinVec::new();
@@ -208,6 +209,21 @@ fn generate_default_impl(
208209
},
209210
span: eii_attr_span,
210211
is_default: true,
212+
known_eii_macro_resolution: Some(ast::EiiExternTarget {
213+
extern_item_path: ast::Path {
214+
span: foreign_item_name.span,
215+
segments: thin_vec![
216+
ast::PathSegment {
217+
ident: Ident::from_str_and_span("super", foreign_item_name.span,),
218+
id: DUMMY_NODE_ID,
219+
args: None
220+
},
221+
ast::PathSegment { ident: foreign_item_name, id: DUMMY_NODE_ID, args: None },
222+
],
223+
tokens: None,
224+
},
225+
impl_unsafe,
226+
}),
211227
});
212228

213229
ast::Item {
@@ -236,18 +252,66 @@ fn generate_default_impl(
236252
stmts: thin_vec![ast::Stmt {
237253
id: DUMMY_NODE_ID,
238254
kind: ast::StmtKind::Item(Box::new(ast::Item {
239-
attrs,
255+
attrs: ThinVec::new(),
240256
id: DUMMY_NODE_ID,
241257
span: item_span,
242258
vis: ast::Visibility {
243-
span: eii_attr_span,
259+
span: item_span,
244260
kind: ast::VisibilityKind::Inherited,
245261
tokens: None
246262
},
247-
kind: ItemKind::Fn(Box::new(default_func)),
263+
kind: ItemKind::Mod(
264+
ast::Safety::Default,
265+
Ident::from_str_and_span("dflt", item_span),
266+
ast::ModKind::Loaded(
267+
thin_vec![
268+
Box::new(ast::Item {
269+
attrs: thin_vec![ecx.attr_nested_word(
270+
sym::allow,
271+
sym::unused_imports,
272+
item_span
273+
),],
274+
id: DUMMY_NODE_ID,
275+
span: item_span,
276+
vis: ast::Visibility {
277+
span: eii_attr_span,
278+
kind: ast::VisibilityKind::Inherited,
279+
tokens: None
280+
},
281+
kind: ItemKind::Use(ast::UseTree {
282+
prefix: ast::Path::from_ident(
283+
Ident::from_str_and_span(
284+
"super", item_span,
285+
)
286+
),
287+
kind: ast::UseTreeKind::Glob,
288+
span: item_span,
289+
}),
290+
tokens: None,
291+
}),
292+
Box::new(ast::Item {
293+
attrs,
294+
id: DUMMY_NODE_ID,
295+
span: item_span,
296+
vis: ast::Visibility {
297+
span: eii_attr_span,
298+
kind: ast::VisibilityKind::Inherited,
299+
tokens: None
300+
},
301+
kind: ItemKind::Fn(Box::new(default_func)),
302+
tokens: None,
303+
}),
304+
],
305+
ast::Inline::Yes,
306+
ast::ModSpans {
307+
inner_span: item_span,
308+
inject_use_span: item_span,
309+
}
310+
)
311+
),
248312
tokens: None,
249313
})),
250-
span: eii_attr_span
314+
span: eii_attr_span,
251315
}],
252316
id: DUMMY_NODE_ID,
253317
rules: ast::BlockCheckMode::Default,
@@ -352,7 +416,6 @@ fn generate_attribute_macro_to_implement(
352416
macro_name: Ident,
353417
foreign_item_name: Ident,
354418
impl_unsafe: bool,
355-
decl_span: Span,
356419
) -> ast::Item {
357420
let mut macro_attrs = ThinVec::new();
358421

@@ -394,7 +457,6 @@ fn generate_attribute_macro_to_implement(
394457
eii_extern_target: Some(ast::EiiExternTarget {
395458
extern_item_path: ast::Path::from_ident(foreign_item_name),
396459
impl_unsafe,
397-
span: decl_span,
398460
}),
399461
},
400462
),
@@ -451,7 +513,7 @@ pub(crate) fn eii_extern_target(
451513
false
452514
};
453515

454-
d.eii_extern_target = Some(EiiExternTarget { extern_item_path, impl_unsafe, span });
516+
d.eii_extern_target = Some(EiiExternTarget { extern_item_path, impl_unsafe });
455517

456518
// Return the original item and the new methods.
457519
vec![item]
@@ -508,6 +570,7 @@ pub(crate) fn eii_shared_macro(
508570
impl_safety: meta_item.unsafety,
509571
span,
510572
is_default,
573+
known_eii_macro_resolution: None,
511574
});
512575

513576
vec![item]

compiler/rustc_codegen_llvm/src/mono_item.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ impl CodegenCx<'_, '_> {
111111
}
112112
}
113113

114-
/// Whether a definition or declaration can be assumed to be local to a group of
114+
/// A definition or declaration can be assumed to be local to a group of
115115
/// libraries that form a single DSO or executable.
116116
/// Marks the local as DSO if so.
117117
pub(crate) fn assume_dso_local(&self, llval: &llvm::Value, is_declaration: bool) -> bool {
@@ -153,7 +153,7 @@ impl CodegenCx<'_, '_> {
153153
return false;
154154
}
155155

156-
// With pie relocation model calls of functions defined in the translation
156+
// With pie relocation model, calls of functions defined in the translation
157157
// unit can use copy relocations.
158158
if self.tcx.sess.relocation_model() == RelocModel::Pie && !is_declaration {
159159
return true;

compiler/rustc_codegen_ssa/src/codegen_attrs.rs

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ use std::str::FromStr;
33
use rustc_abi::{Align, ExternAbi};
44
use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode};
55
use rustc_ast::{LitKind, MetaItem, MetaItemInner, attr};
6-
use rustc_hir::attrs::{AttributeKind, InlineAttr, Linkage, RtsanSetting, UsedBy};
6+
use rustc_hir::attrs::{
7+
AttributeKind, EiiImplResolution, InlineAttr, Linkage, RtsanSetting, UsedBy,
8+
};
79
use rustc_hir::def::DefKind;
810
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
911
use rustc_hir::{self as hir, Attribute, LangItem, find_attr, lang_items};
@@ -285,11 +287,23 @@ fn process_builtin_attrs(
285287
}
286288
AttributeKind::EiiImpls(impls) => {
287289
for i in impls {
288-
let extern_item = find_attr!(
289-
tcx.get_all_attrs(i.eii_macro),
290-
AttributeKind::EiiExternTarget(target) => target.eii_extern_target
291-
)
292-
.expect("eii should have declaration macro with extern target attribute");
290+
let extern_item = match i.resolution {
291+
EiiImplResolution::Macro(def_id) => {
292+
let Some(extern_item) = find_attr!(
293+
tcx.get_all_attrs(def_id),
294+
AttributeKind::EiiExternTarget(target) => target.eii_extern_target
295+
) else {
296+
tcx.dcx().span_delayed_bug(
297+
i.span,
298+
"resolved to something that's not an EII",
299+
);
300+
continue;
301+
};
302+
extern_item
303+
}
304+
EiiImplResolution::Known(decl) => decl.eii_extern_target,
305+
EiiImplResolution::Error(_eg) => continue,
306+
};
293307

294308
// this is to prevent a bug where a single crate defines both the default and explicit implementation
295309
// for an EII. In that case, both of them may be part of the same final object file. I'm not 100% sure
@@ -302,7 +316,7 @@ fn process_builtin_attrs(
302316
// iterate over all implementations *in the current crate*
303317
// (this is ok since we generate codegen fn attrs in the local crate)
304318
// if any of them is *not default* then don't emit the alias.
305-
&& tcx.externally_implementable_items(LOCAL_CRATE).get(&i.eii_macro).expect("at least one").1.iter().any(|(_, imp)| !imp.is_default)
319+
&& tcx.externally_implementable_items(LOCAL_CRATE).get(&extern_item).expect("at least one").1.iter().any(|(_, imp)| !imp.is_default)
306320
{
307321
continue;
308322
}

0 commit comments

Comments
 (0)