mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-02 15:32:06 +00:00
Auto merge of #3023 - RalfJung:gamma, r=RalfJung
add gamma function shims needs a rustup to fetch the new declarations in std
This commit is contained in:
commit
6276e5ad14
3
.github/ISSUE_TEMPLATE/tracking_issue.md
vendored
3
.github/ISSUE_TEMPLATE/tracking_issue.md
vendored
@ -39,10 +39,13 @@ for larger features an implementation could be broken up into multiple PRs.
|
||||
- [ ] Implement the RFC (cc @rust-lang/XXX -- can anyone write up mentoring
|
||||
instructions?)
|
||||
- [ ] Adjust documentation ([see instructions on rustc-dev-guide][doc-guide])
|
||||
- [ ] Formatting for new syntax has been added to the [Style Guide] ([nightly-style-procedure])
|
||||
- [ ] Stabilization PR ([see instructions on rustc-dev-guide][stabilization-guide])
|
||||
|
||||
[stabilization-guide]: https://rustc-dev-guide.rust-lang.org/stabilization_guide.html#stabilization-pr
|
||||
[doc-guide]: https://rustc-dev-guide.rust-lang.org/stabilization_guide.html#documentation-prs
|
||||
[nightly-style-procedure]: https://github.com/rust-lang/style-team/blob/master/nightly-style-procedure.md
|
||||
[Style Guide]: https://github.com/rust-lang/rust/tree/master/src/doc/style-guide
|
||||
|
||||
### Unresolved Questions
|
||||
<!--
|
||||
|
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@ -336,7 +336,7 @@ jobs:
|
||||
os: macos-13
|
||||
- name: x86_64-apple-1
|
||||
env:
|
||||
SCRIPT: "./x.py --stage 2 test --exclude tests/ui --exclude tests/rustdoc --exclude tests/run-make-fulldeps"
|
||||
SCRIPT: "./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc --skip tests/run-make-fulldeps"
|
||||
RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
|
||||
RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
|
||||
MACOSX_DEPLOYMENT_TARGET: 10.8
|
||||
|
@ -641,9 +641,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "compiler_builtins"
|
||||
version = "0.1.98"
|
||||
version = "0.1.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfbefa16407456e5cad1ad066c84dfcb980afe4437103a0007d1c2f136130210"
|
||||
checksum = "d6c0f24437059853f0fa64afc51f338f93647a3de4cf3358ba1bb4171a199775"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"rustc-std-workspace-core",
|
||||
|
@ -313,6 +313,16 @@ pub enum TraitBoundModifier {
|
||||
MaybeConstMaybe,
|
||||
}
|
||||
|
||||
impl TraitBoundModifier {
|
||||
pub fn to_constness(self) -> Const {
|
||||
match self {
|
||||
// FIXME(effects) span
|
||||
Self::MaybeConst => Const::Yes(DUMMY_SP),
|
||||
_ => Const::No,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The AST represents all type param bounds as types.
|
||||
/// `typeck::collect::compute_bounds` matches these against
|
||||
/// the "special" built-in traits (see `middle::lang_items`) and
|
||||
|
@ -207,6 +207,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
&sym.path,
|
||||
ParamMode::Optional,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
hir::InlineAsmOperand::SymStatic { path, def_id }
|
||||
} else {
|
||||
|
@ -31,9 +31,26 @@ pub struct InvalidAbi {
|
||||
pub abi: Symbol,
|
||||
pub command: String,
|
||||
#[subdiagnostic]
|
||||
pub explain: Option<InvalidAbiReason>,
|
||||
#[subdiagnostic]
|
||||
pub suggestion: Option<InvalidAbiSuggestion>,
|
||||
}
|
||||
|
||||
pub struct InvalidAbiReason(pub &'static str);
|
||||
|
||||
impl rustc_errors::AddToDiagnostic for InvalidAbiReason {
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F)
|
||||
where
|
||||
F: Fn(
|
||||
&mut rustc_errors::Diagnostic,
|
||||
rustc_errors::SubdiagnosticMessage,
|
||||
) -> rustc_errors::SubdiagnosticMessage,
|
||||
{
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
diag.note(self.0);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion(
|
||||
ast_lowering_invalid_abi_suggestion,
|
||||
|
@ -100,6 +100,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
ParamMode::Optional,
|
||||
ParenthesizedGenericArgs::Err,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
));
|
||||
let receiver = self.lower_expr(receiver);
|
||||
let args =
|
||||
@ -260,6 +261,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
hir::ExprKind::Path(qpath)
|
||||
}
|
||||
@ -307,6 +309,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
&se.path,
|
||||
ParamMode::Optional,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
)),
|
||||
self.arena
|
||||
.alloc_from_iter(se.fields.iter().map(|x| self.lower_expr_field(x))),
|
||||
@ -1179,6 +1182,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
// Destructure like a tuple struct.
|
||||
let tuple_struct_pat = hir::PatKind::TupleStruct(
|
||||
@ -1198,6 +1202,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
// Destructure like a unit struct.
|
||||
let unit_struct_pat = hir::PatKind::Path(qpath);
|
||||
@ -1222,6 +1227,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
&se.path,
|
||||
ParamMode::Optional,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
let fields_omitted = match &se.rest {
|
||||
StructRest::Base(e) => {
|
||||
|
@ -1,4 +1,4 @@
|
||||
use super::errors::{InvalidAbi, InvalidAbiSuggestion, MisplacedRelaxTraitBound};
|
||||
use super::errors::{InvalidAbi, InvalidAbiReason, InvalidAbiSuggestion, MisplacedRelaxTraitBound};
|
||||
use super::ResolverAstLoweringExt;
|
||||
use super::{AstOwner, ImplTraitContext, ImplTraitPosition};
|
||||
use super::{FnDeclKind, LoweringContext, ParamMode};
|
||||
@ -90,6 +90,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
|
||||
allow_try_trait: Some([sym::try_trait_v2, sym::yeet_desugar_details][..].into()),
|
||||
allow_gen_future,
|
||||
generics_def_id_map: Default::default(),
|
||||
host_param_id: None,
|
||||
};
|
||||
lctx.with_hir_id_owner(owner, |lctx| f(lctx));
|
||||
|
||||
@ -144,8 +145,24 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
|
||||
// This is used to track which lifetimes have already been defined,
|
||||
// and which need to be replicated when lowering an async fn.
|
||||
|
||||
if let hir::ItemKind::Impl(impl_) = parent_hir.node().expect_item().kind {
|
||||
lctx.is_in_trait_impl = impl_.of_trait.is_some();
|
||||
match parent_hir.node().expect_item().kind {
|
||||
hir::ItemKind::Impl(impl_) => {
|
||||
lctx.is_in_trait_impl = impl_.of_trait.is_some();
|
||||
}
|
||||
hir::ItemKind::Trait(_, _, generics, _, _) if lctx.tcx.features().effects => {
|
||||
lctx.host_param_id = generics
|
||||
.params
|
||||
.iter()
|
||||
.find(|param| {
|
||||
parent_hir
|
||||
.attrs
|
||||
.get(param.hir_id.local_id)
|
||||
.iter()
|
||||
.any(|attr| attr.has_name(sym::rustc_host))
|
||||
})
|
||||
.map(|param| param.def_id);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match ctxt {
|
||||
@ -389,6 +406,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
self.lower_generics(ast_generics, *constness, id, &itctx, |this| {
|
||||
let trait_ref = trait_ref.as_ref().map(|trait_ref| {
|
||||
this.lower_trait_ref(
|
||||
*constness,
|
||||
trait_ref,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Trait),
|
||||
)
|
||||
@ -419,7 +437,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
polarity,
|
||||
defaultness,
|
||||
defaultness_span,
|
||||
constness: self.lower_constness(*constness),
|
||||
generics,
|
||||
of_trait: trait_ref,
|
||||
self_ty: lowered_ty,
|
||||
@ -1254,8 +1271,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
}
|
||||
|
||||
pub(super) fn lower_abi(&mut self, abi: StrLit) -> abi::Abi {
|
||||
abi::lookup(abi.symbol_unescaped.as_str()).unwrap_or_else(|| {
|
||||
self.error_on_invalid_abi(abi);
|
||||
abi::lookup(abi.symbol_unescaped.as_str()).unwrap_or_else(|err| {
|
||||
self.error_on_invalid_abi(abi, err);
|
||||
abi::Abi::Rust
|
||||
})
|
||||
}
|
||||
@ -1268,7 +1285,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
}
|
||||
}
|
||||
|
||||
fn error_on_invalid_abi(&self, abi: StrLit) {
|
||||
fn error_on_invalid_abi(&self, abi: StrLit, err: abi::AbiUnsupported) {
|
||||
let abi_names = abi::enabled_names(self.tcx.features(), abi.span)
|
||||
.iter()
|
||||
.map(|s| Symbol::intern(s))
|
||||
@ -1277,6 +1294,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
self.tcx.sess.emit_err(InvalidAbi {
|
||||
abi: abi.symbol_unescaped,
|
||||
span: abi.span,
|
||||
explain: match err {
|
||||
abi::AbiUnsupported::Reason { explain } => Some(InvalidAbiReason(explain)),
|
||||
_ => None,
|
||||
},
|
||||
suggestion: suggested_name.map(|suggested_name| InvalidAbiSuggestion {
|
||||
span: abi.span,
|
||||
suggestion: format!("\"{suggested_name}\""),
|
||||
@ -1363,6 +1384,29 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
}
|
||||
}
|
||||
|
||||
// Desugar `~const` bound in generics into an additional `const host: bool` param
|
||||
// if the effects feature is enabled. This needs to be done before we lower where
|
||||
// clauses since where clauses need to bind to the DefId of the host param
|
||||
let host_param_parts = if let Const::Yes(span) = constness && self.tcx.features().effects {
|
||||
if let Some(param) = generics.params.iter().find(|x| {
|
||||
x.attrs.iter().any(|x| x.has_name(sym::rustc_host))
|
||||
}) {
|
||||
// user has manually specified a `rustc_host` param, in this case, we set
|
||||
// the param id so that lowering logic can use that. But we don't create
|
||||
// another host param, so this gives `None`.
|
||||
self.host_param_id = Some(self.local_def_id(param.id));
|
||||
None
|
||||
} else {
|
||||
let param_node_id = self.next_node_id();
|
||||
let hir_id = self.next_id();
|
||||
let def_id = self.create_def(self.local_def_id(parent_node_id), param_node_id, DefPathData::TypeNs(sym::host), span);
|
||||
self.host_param_id = Some(def_id);
|
||||
Some((span, hir_id, def_id))
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let mut predicates: SmallVec<[hir::WherePredicate<'hir>; 4]> = SmallVec::new();
|
||||
predicates.extend(generics.params.iter().filter_map(|param| {
|
||||
self.lower_generic_bound_predicate(
|
||||
@ -1410,22 +1454,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let impl_trait_bounds = std::mem::take(&mut self.impl_trait_bounds);
|
||||
predicates.extend(impl_trait_bounds.into_iter());
|
||||
|
||||
// Desugar `~const` bound in generics into an additional `const host: bool` param
|
||||
// if the effects feature is enabled.
|
||||
if let Const::Yes(span) = constness && self.tcx.features().effects
|
||||
// Do not add host param if it already has it (manually specified)
|
||||
&& !params.iter().any(|x| {
|
||||
self.attrs.get(&x.hir_id.local_id).map_or(false, |attrs| {
|
||||
attrs.iter().any(|x| x.has_name(sym::rustc_host))
|
||||
})
|
||||
})
|
||||
{
|
||||
let param_node_id = self.next_node_id();
|
||||
if let Some((span, hir_id, def_id)) = host_param_parts {
|
||||
let const_node_id = self.next_node_id();
|
||||
let def_id = self.create_def(self.local_def_id(parent_node_id), param_node_id, DefPathData::TypeNs(sym::host), span);
|
||||
let anon_const: LocalDefId = self.create_def(def_id, const_node_id, DefPathData::AnonConst, span);
|
||||
let anon_const: LocalDefId =
|
||||
self.create_def(def_id, const_node_id, DefPathData::AnonConst, span);
|
||||
|
||||
let hir_id = self.next_id();
|
||||
let const_id = self.next_id();
|
||||
let const_expr_id = self.next_id();
|
||||
let bool_id = self.next_id();
|
||||
@ -1435,14 +1468,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
|
||||
let attr_id = self.tcx.sess.parse_sess.attr_id_generator.mk_attr_id();
|
||||
|
||||
let attrs = self.arena.alloc_from_iter([
|
||||
Attribute {
|
||||
kind: AttrKind::Normal(P(NormalAttr::from_ident(Ident::new(sym::rustc_host, span)))),
|
||||
let attrs = self.arena.alloc_from_iter([Attribute {
|
||||
kind: AttrKind::Normal(P(NormalAttr::from_ident(Ident::new(
|
||||
sym::rustc_host,
|
||||
span,
|
||||
id: attr_id,
|
||||
style: AttrStyle::Outer,
|
||||
},
|
||||
]);
|
||||
)))),
|
||||
span,
|
||||
id: attr_id,
|
||||
style: AttrStyle::Outer,
|
||||
}]);
|
||||
self.attrs.insert(hir_id.local_id, attrs);
|
||||
|
||||
let const_body = self.lower_body(|this| {
|
||||
@ -1481,7 +1515,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
}),
|
||||
)),
|
||||
)),
|
||||
default: Some(hir::AnonConst { def_id: anon_const, hir_id: const_id, body: const_body }),
|
||||
default: Some(hir::AnonConst {
|
||||
def_id: anon_const,
|
||||
hir_id: const_id,
|
||||
body: const_body,
|
||||
}),
|
||||
},
|
||||
colon_span: None,
|
||||
pure_wrt_drop: false,
|
||||
|
@ -142,6 +142,8 @@ struct LoweringContext<'a, 'hir> {
|
||||
/// defined on the TAIT, so we have type Foo<'a1> = ... and we establish a mapping in this
|
||||
/// field from the original parameter 'a to the new parameter 'a1.
|
||||
generics_def_id_map: Vec<FxHashMap<LocalDefId, LocalDefId>>,
|
||||
|
||||
host_param_id: Option<LocalDefId>,
|
||||
}
|
||||
|
||||
trait ResolverAstLoweringExt {
|
||||
@ -1262,6 +1264,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
span: t.span
|
||||
},
|
||||
itctx,
|
||||
ast::Const::No,
|
||||
);
|
||||
let bounds = this.arena.alloc_from_iter([bound]);
|
||||
let lifetime_bound = this.elided_dyn_bound(t.span);
|
||||
@ -1272,7 +1275,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
}
|
||||
|
||||
let id = self.lower_node_id(t.id);
|
||||
let qpath = self.lower_qpath(t.id, qself, path, param_mode, itctx);
|
||||
let qpath = self.lower_qpath(t.id, qself, path, param_mode, itctx, None);
|
||||
self.ty_path(id, t.span, qpath)
|
||||
}
|
||||
|
||||
@ -1356,10 +1359,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
this.arena.alloc_from_iter(bounds.iter().filter_map(|bound| match bound {
|
||||
GenericBound::Trait(
|
||||
ty,
|
||||
TraitBoundModifier::None
|
||||
modifier @ (TraitBoundModifier::None
|
||||
| TraitBoundModifier::MaybeConst
|
||||
| TraitBoundModifier::Negative,
|
||||
) => Some(this.lower_poly_trait_ref(ty, itctx)),
|
||||
| TraitBoundModifier::Negative),
|
||||
) => {
|
||||
Some(this.lower_poly_trait_ref(ty, itctx, modifier.to_constness()))
|
||||
}
|
||||
// `~const ?Bound` will cause an error during AST validation
|
||||
// anyways, so treat it like `?Bound` as compilation proceeds.
|
||||
GenericBound::Trait(
|
||||
@ -1663,11 +1668,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
);
|
||||
debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params);
|
||||
|
||||
let lifetime_mapping = if in_trait {
|
||||
Some(&*self.arena.alloc_slice(&synthesized_lifetime_args))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let lifetime_mapping = self.arena.alloc_slice(&synthesized_lifetime_args);
|
||||
|
||||
let opaque_ty_item = hir::OpaqueTy {
|
||||
generics: this.arena.alloc(hir::Generics {
|
||||
@ -1956,7 +1957,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
) -> hir::GenericBound<'hir> {
|
||||
match tpb {
|
||||
GenericBound::Trait(p, modifier) => hir::GenericBound::Trait(
|
||||
self.lower_poly_trait_ref(p, itctx),
|
||||
self.lower_poly_trait_ref(p, itctx, modifier.to_constness()),
|
||||
self.lower_trait_bound_modifier(*modifier),
|
||||
),
|
||||
GenericBound::Outlives(lifetime) => {
|
||||
@ -2099,8 +2100,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_trait_ref(&mut self, p: &TraitRef, itctx: &ImplTraitContext) -> hir::TraitRef<'hir> {
|
||||
let path = match self.lower_qpath(p.ref_id, &None, &p.path, ParamMode::Explicit, itctx) {
|
||||
fn lower_trait_ref(
|
||||
&mut self,
|
||||
constness: ast::Const,
|
||||
p: &TraitRef,
|
||||
itctx: &ImplTraitContext,
|
||||
) -> hir::TraitRef<'hir> {
|
||||
let path = match self.lower_qpath(
|
||||
p.ref_id,
|
||||
&None,
|
||||
&p.path,
|
||||
ParamMode::Explicit,
|
||||
itctx,
|
||||
Some(constness),
|
||||
) {
|
||||
hir::QPath::Resolved(None, path) => path,
|
||||
qpath => panic!("lower_trait_ref: unexpected QPath `{qpath:?}`"),
|
||||
};
|
||||
@ -2112,10 +2125,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
&mut self,
|
||||
p: &PolyTraitRef,
|
||||
itctx: &ImplTraitContext,
|
||||
constness: ast::Const,
|
||||
) -> hir::PolyTraitRef<'hir> {
|
||||
let bound_generic_params =
|
||||
self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params);
|
||||
let trait_ref = self.lower_trait_ref(&p.trait_ref, itctx);
|
||||
let trait_ref = self.lower_trait_ref(constness, &p.trait_ref, itctx);
|
||||
hir::PolyTraitRef { bound_generic_params, trait_ref, span: self.lower_span(p.span) }
|
||||
}
|
||||
|
||||
@ -2469,6 +2483,67 @@ struct GenericArgsCtor<'hir> {
|
||||
}
|
||||
|
||||
impl<'hir> GenericArgsCtor<'hir> {
|
||||
fn push_constness(&mut self, lcx: &mut LoweringContext<'_, 'hir>, constness: ast::Const) {
|
||||
if !lcx.tcx.features().effects {
|
||||
return;
|
||||
}
|
||||
|
||||
// if bound is non-const, don't add host effect param
|
||||
let ast::Const::Yes(span) = constness else { return };
|
||||
|
||||
let span = lcx.lower_span(span);
|
||||
|
||||
let id = lcx.next_node_id();
|
||||
let hir_id = lcx.next_id();
|
||||
let body = lcx.lower_body(|lcx| {
|
||||
(
|
||||
&[],
|
||||
match constness {
|
||||
ast::Const::Yes(_) => {
|
||||
let hir_id = lcx.next_id();
|
||||
let res =
|
||||
Res::Def(DefKind::ConstParam, lcx.host_param_id.unwrap().to_def_id());
|
||||
let expr_kind = hir::ExprKind::Path(hir::QPath::Resolved(
|
||||
None,
|
||||
lcx.arena.alloc(hir::Path {
|
||||
span,
|
||||
res,
|
||||
segments: arena_vec![lcx; hir::PathSegment::new(Ident {
|
||||
name: sym::host,
|
||||
span,
|
||||
}, hir_id, res)],
|
||||
}),
|
||||
));
|
||||
lcx.expr(span, expr_kind)
|
||||
}
|
||||
ast::Const::No => lcx.expr(
|
||||
span,
|
||||
hir::ExprKind::Lit(
|
||||
lcx.arena.alloc(hir::Lit { span, node: ast::LitKind::Bool(true) }),
|
||||
),
|
||||
),
|
||||
},
|
||||
)
|
||||
});
|
||||
|
||||
let attr_id = lcx.tcx.sess.parse_sess.attr_id_generator.mk_attr_id();
|
||||
let attr = lcx.arena.alloc(Attribute {
|
||||
kind: AttrKind::Normal(P(NormalAttr::from_ident(Ident::new(sym::rustc_host, span)))),
|
||||
span,
|
||||
id: attr_id,
|
||||
style: AttrStyle::Outer,
|
||||
});
|
||||
lcx.attrs.insert(hir_id.local_id, std::slice::from_ref(attr));
|
||||
|
||||
let def_id =
|
||||
lcx.create_def(lcx.current_hir_id_owner.def_id, id, DefPathData::AnonConst, span);
|
||||
lcx.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id)));
|
||||
self.args.push(hir::GenericArg::Const(hir::ConstArg {
|
||||
value: hir::AnonConst { def_id, hir_id, body },
|
||||
span,
|
||||
}))
|
||||
}
|
||||
|
||||
fn is_empty(&self) -> bool {
|
||||
self.args.is_empty()
|
||||
&& self.bindings.is_empty()
|
||||
|
@ -38,6 +38,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct");
|
||||
break hir::PatKind::TupleStruct(qpath, pats, ddpos);
|
||||
@ -54,6 +55,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
break hir::PatKind::Path(qpath);
|
||||
}
|
||||
@ -64,6 +66,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
|
||||
let fs = self.arena.alloc_from_iter(fields.iter().map(|f| {
|
||||
|
@ -23,6 +23,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
p: &Path,
|
||||
param_mode: ParamMode,
|
||||
itctx: &ImplTraitContext,
|
||||
// constness of the impl/bound if this is a trait path
|
||||
constness: Option<ast::Const>,
|
||||
) -> hir::QPath<'hir> {
|
||||
let qself_position = qself.as_ref().map(|q| q.position);
|
||||
let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx));
|
||||
@ -73,6 +75,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
param_mode,
|
||||
parenthesized_generic_args,
|
||||
itctx,
|
||||
// if this is the last segment, add constness to the trait path
|
||||
if i == proj_start - 1 { constness } else { None },
|
||||
)
|
||||
},
|
||||
)),
|
||||
@ -119,6 +123,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
param_mode,
|
||||
ParenthesizedGenericArgs::Err,
|
||||
itctx,
|
||||
None,
|
||||
));
|
||||
let qpath = hir::QPath::TypeRelative(ty, hir_segment);
|
||||
|
||||
@ -159,6 +164,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
param_mode,
|
||||
ParenthesizedGenericArgs::Err,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
)
|
||||
})),
|
||||
span: self.lower_span(p.span),
|
||||
@ -172,8 +178,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
param_mode: ParamMode,
|
||||
parenthesized_generic_args: ParenthesizedGenericArgs,
|
||||
itctx: &ImplTraitContext,
|
||||
constness: Option<ast::Const>,
|
||||
) -> hir::PathSegment<'hir> {
|
||||
debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment,);
|
||||
debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment);
|
||||
let (mut generic_args, infer_args) = if let Some(generic_args) = segment.args.as_deref() {
|
||||
match generic_args {
|
||||
GenericArgs::AngleBracketed(data) => {
|
||||
@ -231,6 +238,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
)
|
||||
};
|
||||
|
||||
if let Some(constness) = constness {
|
||||
generic_args.push_constness(self, constness);
|
||||
}
|
||||
|
||||
let has_lifetimes =
|
||||
generic_args.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_)));
|
||||
|
||||
|
19
compiler/rustc_codegen_cranelift/.github/workflows/audit.yml
vendored
Normal file
19
compiler/rustc_codegen_cranelift/.github/workflows/audit.yml
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
name: Security audit
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 10 * * 1' # every monday at 10:00 UTC
|
||||
permissions:
|
||||
issues: write
|
||||
checks: write
|
||||
jobs:
|
||||
audit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- run: |
|
||||
sed -i 's/components.*/components = []/' rust-toolchain
|
||||
echo 'profile = "minimal"' >> rust-toolchain
|
||||
- uses: rustsec/audit-check@v1.4.1
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
@ -1,8 +1,8 @@
|
||||
use super::build_sysroot;
|
||||
use super::path::Dirs;
|
||||
use super::prepare::GitRepo;
|
||||
use super::utils::{spawn_and_wait, CargoProject, Compiler};
|
||||
use super::{CodegenBackend, SysrootKind};
|
||||
use crate::build_sysroot;
|
||||
use crate::path::Dirs;
|
||||
use crate::prepare::GitRepo;
|
||||
use crate::utils::{spawn_and_wait, CargoProject, Compiler};
|
||||
use crate::{CodegenBackend, SysrootKind};
|
||||
|
||||
static ABI_CAFE_REPO: GitRepo = GitRepo::github(
|
||||
"Gankra",
|
||||
|
@ -2,10 +2,10 @@ use std::env;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
|
||||
use super::path::{Dirs, RelPath};
|
||||
use super::prepare::GitRepo;
|
||||
use super::rustc_info::get_file_name;
|
||||
use super::utils::{hyperfine_command, spawn_and_wait, Compiler};
|
||||
use crate::path::{Dirs, RelPath};
|
||||
use crate::prepare::GitRepo;
|
||||
use crate::rustc_info::get_file_name;
|
||||
use crate::utils::{hyperfine_command, spawn_and_wait, Compiler};
|
||||
|
||||
static SIMPLE_RAYTRACER_REPO: GitRepo = GitRepo::github(
|
||||
"ebobby",
|
||||
|
@ -1,9 +1,9 @@
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use super::path::{Dirs, RelPath};
|
||||
use super::rustc_info::get_file_name;
|
||||
use super::utils::{is_ci, is_ci_opt, maybe_incremental, CargoProject, Compiler, LogGroup};
|
||||
use crate::path::{Dirs, RelPath};
|
||||
use crate::rustc_info::get_file_name;
|
||||
use crate::shared_utils::{rustflags_from_env, rustflags_to_cmd_env};
|
||||
use crate::utils::{is_ci, is_ci_opt, maybe_incremental, CargoProject, Compiler, LogGroup};
|
||||
|
||||
pub(crate) static CG_CLIF: CargoProject = CargoProject::new(&RelPath::SOURCE, "cg_clif");
|
||||
|
||||
@ -18,11 +18,11 @@ pub(crate) fn build_backend(
|
||||
let mut cmd = CG_CLIF.build(&bootstrap_host_compiler, dirs);
|
||||
maybe_incremental(&mut cmd);
|
||||
|
||||
let mut rustflags = env::var("RUSTFLAGS").unwrap_or_default();
|
||||
let mut rustflags = rustflags_from_env("RUSTFLAGS");
|
||||
|
||||
if is_ci() {
|
||||
// Deny warnings on CI
|
||||
rustflags += " -Dwarnings";
|
||||
rustflags.push("-Dwarnings".to_owned());
|
||||
|
||||
if !is_ci_opt() {
|
||||
cmd.env("CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS", "true");
|
||||
@ -42,10 +42,10 @@ pub(crate) fn build_backend(
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
cmd.env("RUSTFLAGS", rustflags);
|
||||
rustflags_to_cmd_env(&mut cmd, "RUSTFLAGS", &rustflags);
|
||||
|
||||
eprintln!("[BUILD] rustc_codegen_cranelift");
|
||||
super::utils::spawn_and_wait(cmd);
|
||||
crate::utils::spawn_and_wait(cmd);
|
||||
|
||||
CG_CLIF
|
||||
.target_dir(dirs)
|
||||
|
@ -2,13 +2,13 @@ use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
|
||||
use super::path::{Dirs, RelPath};
|
||||
use super::rustc_info::get_file_name;
|
||||
use super::utils::{
|
||||
use crate::path::{Dirs, RelPath};
|
||||
use crate::rustc_info::get_file_name;
|
||||
use crate::utils::{
|
||||
maybe_incremental, remove_dir_if_exists, spawn_and_wait, try_hard_link, CargoProject, Compiler,
|
||||
LogGroup,
|
||||
};
|
||||
use super::{CodegenBackend, SysrootKind};
|
||||
use crate::{config, CodegenBackend, SysrootKind};
|
||||
|
||||
static DIST_DIR: RelPath = RelPath::DIST;
|
||||
static BIN_DIR: RelPath = RelPath::DIST.join("bin");
|
||||
@ -128,8 +128,8 @@ pub(crate) fn build_sysroot(
|
||||
cargo: bootstrap_host_compiler.cargo.clone(),
|
||||
rustc: rustc_clif.clone(),
|
||||
rustdoc: rustdoc_clif.clone(),
|
||||
rustflags: String::new(),
|
||||
rustdocflags: String::new(),
|
||||
rustflags: vec![],
|
||||
rustdocflags: vec![],
|
||||
triple: target_triple,
|
||||
runner: vec![],
|
||||
}
|
||||
@ -185,7 +185,7 @@ fn build_sysroot_for_triple(
|
||||
|
||||
#[must_use]
|
||||
fn build_llvm_sysroot_for_triple(compiler: Compiler) -> SysrootTarget {
|
||||
let default_sysroot = super::rustc_info::get_default_sysroot(&compiler.rustc);
|
||||
let default_sysroot = crate::rustc_info::get_default_sysroot(&compiler.rustc);
|
||||
|
||||
let mut target_libs = SysrootTarget { triple: compiler.triple, libs: vec![] };
|
||||
|
||||
@ -234,32 +234,32 @@ fn build_clif_sysroot_for_triple(
|
||||
|
||||
let build_dir = STANDARD_LIBRARY.target_dir(dirs).join(&compiler.triple).join(channel);
|
||||
|
||||
if !super::config::get_bool("keep_sysroot") {
|
||||
if !config::get_bool("keep_sysroot") {
|
||||
// Cleanup the deps dir, but keep build scripts and the incremental cache for faster
|
||||
// recompilation as they are not affected by changes in cg_clif.
|
||||
remove_dir_if_exists(&build_dir.join("deps"));
|
||||
}
|
||||
|
||||
// Build sysroot
|
||||
let mut rustflags = " -Zforce-unstable-if-unmarked -Cpanic=abort".to_string();
|
||||
let mut rustflags = vec!["-Zforce-unstable-if-unmarked".to_owned(), "-Cpanic=abort".to_owned()];
|
||||
match cg_clif_dylib_path {
|
||||
CodegenBackend::Local(path) => {
|
||||
rustflags.push_str(&format!(" -Zcodegen-backend={}", path.to_str().unwrap()));
|
||||
rustflags.push(format!("-Zcodegen-backend={}", path.to_str().unwrap()));
|
||||
}
|
||||
CodegenBackend::Builtin(name) => {
|
||||
rustflags.push_str(&format!(" -Zcodegen-backend={name}"));
|
||||
rustflags.push(format!("-Zcodegen-backend={name}"));
|
||||
}
|
||||
};
|
||||
// Necessary for MinGW to find rsbegin.o and rsend.o
|
||||
rustflags
|
||||
.push_str(&format!(" --sysroot {}", RTSTARTUP_SYSROOT.to_path(dirs).to_str().unwrap()));
|
||||
rustflags.push("--sysroot".to_owned());
|
||||
rustflags.push(RTSTARTUP_SYSROOT.to_path(dirs).to_str().unwrap().to_owned());
|
||||
if channel == "release" {
|
||||
// Incremental compilation by default disables mir inlining. This leads to both a decent
|
||||
// compile perf and a significant runtime perf regression. As such forcefully enable mir
|
||||
// inlining.
|
||||
rustflags.push_str(" -Zinline-mir");
|
||||
rustflags.push("-Zinline-mir".to_owned());
|
||||
}
|
||||
compiler.rustflags += &rustflags;
|
||||
compiler.rustflags.extend(rustflags);
|
||||
let mut build_cmd = STANDARD_LIBRARY.build(&compiler, dirs);
|
||||
maybe_incremental(&mut build_cmd);
|
||||
if channel == "release" {
|
||||
@ -289,8 +289,8 @@ fn build_clif_sysroot_for_triple(
|
||||
}
|
||||
|
||||
fn build_rtstartup(dirs: &Dirs, compiler: &Compiler) -> Option<SysrootTarget> {
|
||||
if !super::config::get_bool("keep_sysroot") {
|
||||
super::prepare::prepare_stdlib(dirs, &compiler.rustc);
|
||||
if !config::get_bool("keep_sysroot") {
|
||||
crate::prepare::prepare_stdlib(dirs, &compiler.rustc);
|
||||
}
|
||||
|
||||
if !compiler.triple.ends_with("windows-gnu") {
|
||||
@ -306,6 +306,7 @@ fn build_rtstartup(dirs: &Dirs, compiler: &Compiler) -> Option<SysrootTarget> {
|
||||
let obj = RTSTARTUP_SYSROOT.to_path(dirs).join(format!("{file}.o"));
|
||||
let mut build_rtstartup_cmd = Command::new(&compiler.rustc);
|
||||
build_rtstartup_cmd
|
||||
.arg("-Ainternal_features") // Missing #[allow(internal_features)]
|
||||
.arg("--target")
|
||||
.arg(&compiler.triple)
|
||||
.arg("--emit=obj")
|
||||
|
@ -16,6 +16,7 @@ mod config;
|
||||
mod path;
|
||||
mod prepare;
|
||||
mod rustc_info;
|
||||
mod shared_utils;
|
||||
mod tests;
|
||||
mod utils;
|
||||
|
||||
@ -169,8 +170,8 @@ fn main() {
|
||||
cargo,
|
||||
rustc,
|
||||
rustdoc,
|
||||
rustflags: String::new(),
|
||||
rustdocflags: String::new(),
|
||||
rustflags: vec![],
|
||||
rustdocflags: vec![],
|
||||
triple,
|
||||
runner: vec![],
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use super::utils::remove_dir_if_exists;
|
||||
use crate::utils::remove_dir_if_exists;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct Dirs {
|
||||
|
@ -3,18 +3,18 @@ use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
|
||||
use super::build_sysroot::STDLIB_SRC;
|
||||
use super::path::{Dirs, RelPath};
|
||||
use super::rustc_info::get_default_sysroot;
|
||||
use super::utils::{
|
||||
use crate::build_sysroot::STDLIB_SRC;
|
||||
use crate::path::{Dirs, RelPath};
|
||||
use crate::rustc_info::get_default_sysroot;
|
||||
use crate::utils::{
|
||||
copy_dir_recursively, git_command, remove_dir_if_exists, retry_spawn_and_wait, spawn_and_wait,
|
||||
};
|
||||
|
||||
pub(crate) fn prepare(dirs: &Dirs) {
|
||||
RelPath::DOWNLOAD.ensure_exists(dirs);
|
||||
super::tests::RAND_REPO.fetch(dirs);
|
||||
super::tests::REGEX_REPO.fetch(dirs);
|
||||
super::tests::PORTABLE_SIMD_REPO.fetch(dirs);
|
||||
crate::tests::RAND_REPO.fetch(dirs);
|
||||
crate::tests::REGEX_REPO.fetch(dirs);
|
||||
crate::tests::PORTABLE_SIMD_REPO.fetch(dirs);
|
||||
}
|
||||
|
||||
pub(crate) fn prepare_stdlib(dirs: &Dirs, rustc: &Path) {
|
||||
|
@ -0,0 +1,26 @@
|
||||
// This file is used by both the build system as well as cargo-clif.rs
|
||||
|
||||
// Adapted from https://github.com/rust-lang/cargo/blob/6dc1deaddf62c7748c9097c7ea88e9ec77ff1a1a/src/cargo/core/compiler/build_context/target_info.rs#L750-L77
|
||||
pub(crate) fn rustflags_from_env(kind: &str) -> Vec<String> {
|
||||
// First try CARGO_ENCODED_RUSTFLAGS from the environment.
|
||||
// Prefer this over RUSTFLAGS since it's less prone to encoding errors.
|
||||
if let Ok(a) = std::env::var(format!("CARGO_ENCODED_{}", kind)) {
|
||||
if a.is_empty() {
|
||||
return Vec::new();
|
||||
}
|
||||
return a.split('\x1f').map(str::to_string).collect();
|
||||
}
|
||||
|
||||
// Then try RUSTFLAGS from the environment
|
||||
if let Ok(a) = std::env::var(kind) {
|
||||
let args = a.split(' ').map(str::trim).filter(|s| !s.is_empty()).map(str::to_string);
|
||||
return args.collect();
|
||||
}
|
||||
|
||||
// No rustflags to be collected from the environment
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
pub(crate) fn rustflags_to_cmd_env(cmd: &mut std::process::Command, kind: &str, flags: &[String]) {
|
||||
cmd.env(format!("CARGO_ENCODED_{}", kind), flags.join("\x1f"));
|
||||
}
|
@ -1,16 +1,17 @@
|
||||
use super::build_sysroot;
|
||||
use super::config;
|
||||
use super::path::{Dirs, RelPath};
|
||||
use super::prepare::{apply_patches, GitRepo};
|
||||
use super::rustc_info::get_default_sysroot;
|
||||
use super::utils::{spawn_and_wait, spawn_and_wait_with_input, CargoProject, Compiler, LogGroup};
|
||||
use super::{CodegenBackend, SysrootKind};
|
||||
use std::env;
|
||||
use std::ffi::OsStr;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
|
||||
use crate::build_sysroot;
|
||||
use crate::config;
|
||||
use crate::path::{Dirs, RelPath};
|
||||
use crate::prepare::{apply_patches, GitRepo};
|
||||
use crate::rustc_info::get_default_sysroot;
|
||||
use crate::shared_utils::rustflags_from_env;
|
||||
use crate::utils::{spawn_and_wait, spawn_and_wait_with_input, CargoProject, Compiler, LogGroup};
|
||||
use crate::{CodegenBackend, SysrootKind};
|
||||
|
||||
static BUILD_EXAMPLE_OUT_DIR: RelPath = RelPath::BUILD.join("example");
|
||||
|
||||
struct TestCase {
|
||||
@ -306,7 +307,7 @@ pub(crate) fn run_tests(
|
||||
);
|
||||
// Rust's build system denies a couple of lints that trigger on several of the test
|
||||
// projects. Changing the code to fix them is not worth it, so just silence all lints.
|
||||
target_compiler.rustflags += " --cap-lints=allow";
|
||||
target_compiler.rustflags.push("--cap-lints=allow".to_owned());
|
||||
|
||||
let runner = TestRunner::new(
|
||||
dirs.clone(),
|
||||
@ -350,18 +351,15 @@ impl<'a> TestRunner<'a> {
|
||||
is_native: bool,
|
||||
stdlib_source: PathBuf,
|
||||
) -> Self {
|
||||
if let Ok(rustflags) = env::var("RUSTFLAGS") {
|
||||
target_compiler.rustflags.push(' ');
|
||||
target_compiler.rustflags.push_str(&rustflags);
|
||||
}
|
||||
if let Ok(rustdocflags) = env::var("RUSTDOCFLAGS") {
|
||||
target_compiler.rustdocflags.push(' ');
|
||||
target_compiler.rustdocflags.push_str(&rustdocflags);
|
||||
}
|
||||
target_compiler.rustflags.extend(rustflags_from_env("RUSTFLAGS"));
|
||||
target_compiler.rustdocflags.extend(rustflags_from_env("RUSTDOCFLAGS"));
|
||||
|
||||
// FIXME fix `#[linkage = "extern_weak"]` without this
|
||||
if target_compiler.triple.contains("darwin") {
|
||||
target_compiler.rustflags.push_str(" -Clink-arg=-undefined -Clink-arg=dynamic_lookup");
|
||||
target_compiler.rustflags.extend([
|
||||
"-Clink-arg=-undefined".to_owned(),
|
||||
"-Clink-arg=dynamic_lookup".to_owned(),
|
||||
]);
|
||||
}
|
||||
|
||||
let jit_supported = use_unstable_features
|
||||
@ -470,7 +468,7 @@ impl<'a> TestRunner<'a> {
|
||||
S: AsRef<OsStr>,
|
||||
{
|
||||
let mut cmd = Command::new(&self.target_compiler.rustc);
|
||||
cmd.args(self.target_compiler.rustflags.split_whitespace());
|
||||
cmd.args(&self.target_compiler.rustflags);
|
||||
cmd.arg("-L");
|
||||
cmd.arg(format!("crate={}", BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).display()));
|
||||
cmd.arg("--out-dir");
|
||||
|
@ -43,7 +43,7 @@ REQUIREMENTS:
|
||||
* Rustup: By default rustup is used to install the right nightly version. If you don't want to
|
||||
use rustup, you can manually install the nightly version indicated by rust-toolchain.toml and
|
||||
point the CARGO, RUSTC and RUSTDOC env vars to the right executables.
|
||||
* Git: `./y.sh prepare` uses git for applying patches and on Windows for downloading test repos.
|
||||
* Git: Git is used for applying patches and on Windows for downloading test repos.
|
||||
* Curl and tar (non-Windows only): Used by `./y.sh prepare` to download a single commit for
|
||||
repos. Git will be used to clone the whole repo when using Windows.
|
||||
* [Hyperfine](https://github.com/sharkdp/hyperfine/): Used for benchmarking with `./y.sh bench`.
|
||||
|
@ -5,15 +5,16 @@ use std::path::{Path, PathBuf};
|
||||
use std::process::{self, Command, Stdio};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
use super::path::{Dirs, RelPath};
|
||||
use crate::path::{Dirs, RelPath};
|
||||
use crate::shared_utils::rustflags_to_cmd_env;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct Compiler {
|
||||
pub(crate) cargo: PathBuf,
|
||||
pub(crate) rustc: PathBuf,
|
||||
pub(crate) rustdoc: PathBuf,
|
||||
pub(crate) rustflags: String,
|
||||
pub(crate) rustdocflags: String,
|
||||
pub(crate) rustflags: Vec<String>,
|
||||
pub(crate) rustdocflags: Vec<String>,
|
||||
pub(crate) triple: String,
|
||||
pub(crate) runner: Vec<String>,
|
||||
}
|
||||
@ -23,8 +24,8 @@ impl Compiler {
|
||||
match self.triple.as_str() {
|
||||
"aarch64-unknown-linux-gnu" => {
|
||||
// We are cross-compiling for aarch64. Use the correct linker and run tests in qemu.
|
||||
self.rustflags += " -Clinker=aarch64-linux-gnu-gcc";
|
||||
self.rustdocflags += " -Clinker=aarch64-linux-gnu-gcc";
|
||||
self.rustflags.push("-Clinker=aarch64-linux-gnu-gcc".to_owned());
|
||||
self.rustdocflags.push("-Clinker=aarch64-linux-gnu-gcc".to_owned());
|
||||
self.runner = vec![
|
||||
"qemu-aarch64".to_owned(),
|
||||
"-L".to_owned(),
|
||||
@ -33,8 +34,8 @@ impl Compiler {
|
||||
}
|
||||
"s390x-unknown-linux-gnu" => {
|
||||
// We are cross-compiling for s390x. Use the correct linker and run tests in qemu.
|
||||
self.rustflags += " -Clinker=s390x-linux-gnu-gcc";
|
||||
self.rustdocflags += " -Clinker=s390x-linux-gnu-gcc";
|
||||
self.rustflags.push("-Clinker=s390x-linux-gnu-gcc".to_owned());
|
||||
self.rustdocflags.push("-Clinker=s390x-linux-gnu-gcc".to_owned());
|
||||
self.runner = vec![
|
||||
"qemu-s390x".to_owned(),
|
||||
"-L".to_owned(),
|
||||
@ -100,8 +101,8 @@ impl CargoProject {
|
||||
|
||||
cmd.env("RUSTC", &compiler.rustc);
|
||||
cmd.env("RUSTDOC", &compiler.rustdoc);
|
||||
cmd.env("RUSTFLAGS", &compiler.rustflags);
|
||||
cmd.env("RUSTDOCFLAGS", &compiler.rustdocflags);
|
||||
rustflags_to_cmd_env(&mut cmd, "RUSTFLAGS", &compiler.rustflags);
|
||||
rustflags_to_cmd_env(&mut cmd, "RUSTDOCFLAGS", &compiler.rustdocflags);
|
||||
if !compiler.runner.is_empty() {
|
||||
cmd.env(
|
||||
format!("CARGO_TARGET_{}_RUNNER", compiler.triple.to_uppercase().replace('-', "_")),
|
||||
|
@ -11,7 +11,7 @@
|
||||
thread_local
|
||||
)]
|
||||
#![no_core]
|
||||
#![allow(dead_code)]
|
||||
#![allow(dead_code, internal_features)]
|
||||
|
||||
#[lang = "sized"]
|
||||
pub trait Sized {}
|
||||
|
@ -1,6 +1,6 @@
|
||||
#![feature(no_core, lang_items, never_type, linkage, extern_types, thread_local, repr_simd)]
|
||||
#![no_core]
|
||||
#![allow(dead_code, non_camel_case_types)]
|
||||
#![allow(dead_code, non_camel_case_types, internal_features)]
|
||||
|
||||
extern crate mini_core;
|
||||
|
||||
|
@ -0,0 +1,24 @@
|
||||
From fcf75306d88e533b83eaff3f8d0ab9f307e8a84d Mon Sep 17 00:00:00 2001
|
||||
From: bjorn3 <17426603+bjorn3@users.noreply.github.com>
|
||||
Date: Wed, 9 Aug 2023 10:01:17 +0000
|
||||
Subject: [PATCH] Allow internal features
|
||||
|
||||
---
|
||||
crates/core_simd/src/lib.rs | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/crates/core_simd/src/lib.rs b/crates/core_simd/src/lib.rs
|
||||
index fde406b..b386116 100644
|
||||
--- a/crates/core_simd/src/lib.rs
|
||||
+++ b/crates/core_simd/src/lib.rs
|
||||
@@ -19,6 +19,7 @@
|
||||
#![warn(missing_docs, clippy::missing_inline_in_public_items)] // basically all items, really
|
||||
#![deny(unsafe_op_in_unsafe_fn, clippy::undocumented_unsafe_blocks)]
|
||||
#![unstable(feature = "portable_simd", issue = "86656")]
|
||||
+#![allow(internal_features)]
|
||||
//! Portable SIMD module.
|
||||
|
||||
#[path = "mod.rs"]
|
||||
--
|
||||
2.34.1
|
||||
|
@ -74,9 +74,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "compiler_builtins"
|
||||
version = "0.1.95"
|
||||
version = "0.1.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6866e0f3638013234db3c89ead7a14d278354338e7237257407500009012b23f"
|
||||
checksum = "d6c0f24437059853f0fa64afc51f338f93647a3de4cf3358ba1bb4171a199775"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"rustc-std-workspace-core",
|
||||
|
@ -1,3 +1,3 @@
|
||||
[toolchain]
|
||||
channel = "nightly-2023-07-22"
|
||||
channel = "nightly-2023-08-08"
|
||||
components = ["rust-src", "rustc-dev", "llvm-tools"]
|
||||
|
@ -3,6 +3,8 @@ use std::env;
|
||||
use std::os::unix::process::CommandExt;
|
||||
use std::process::Command;
|
||||
|
||||
include!("../build_system/shared_utils.rs");
|
||||
|
||||
fn main() {
|
||||
let current_exe = env::current_exe().unwrap();
|
||||
let mut sysroot = current_exe.parent().unwrap();
|
||||
@ -10,27 +12,19 @@ fn main() {
|
||||
sysroot = sysroot.parent().unwrap();
|
||||
}
|
||||
|
||||
let mut rustflags = String::new();
|
||||
rustflags.push_str(" -Cpanic=abort -Zpanic-abort-tests -Zcodegen-backend=");
|
||||
let mut rustflags = vec!["-Cpanic=abort".to_owned(), "-Zpanic-abort-tests".to_owned()];
|
||||
if let Some(name) = option_env!("BUILTIN_BACKEND") {
|
||||
rustflags.push_str(name);
|
||||
rustflags.push(format!("-Zcodegen-backend={name}"));
|
||||
} else {
|
||||
rustflags.push_str(
|
||||
sysroot
|
||||
.join(if cfg!(windows) { "bin" } else { "lib" })
|
||||
.join(
|
||||
env::consts::DLL_PREFIX.to_string()
|
||||
+ "rustc_codegen_cranelift"
|
||||
+ env::consts::DLL_SUFFIX,
|
||||
)
|
||||
.to_str()
|
||||
.unwrap(),
|
||||
let dylib = sysroot.join(if cfg!(windows) { "bin" } else { "lib" }).join(
|
||||
env::consts::DLL_PREFIX.to_string()
|
||||
+ "rustc_codegen_cranelift"
|
||||
+ env::consts::DLL_SUFFIX,
|
||||
);
|
||||
rustflags.push(format!("-Zcodegen-backend={}", dylib.to_str().unwrap()));
|
||||
}
|
||||
rustflags.push_str(" --sysroot ");
|
||||
rustflags.push_str(sysroot.to_str().unwrap());
|
||||
env::set_var("RUSTFLAGS", env::var("RUSTFLAGS").unwrap_or(String::new()) + &rustflags);
|
||||
env::set_var("RUSTDOCFLAGS", env::var("RUSTDOCFLAGS").unwrap_or(String::new()) + &rustflags);
|
||||
rustflags.push("--sysroot".to_owned());
|
||||
rustflags.push(sysroot.to_str().unwrap().to_owned());
|
||||
|
||||
let cargo = if let Some(cargo) = option_env!("CARGO") {
|
||||
cargo
|
||||
@ -49,10 +43,7 @@ fn main() {
|
||||
|
||||
let args: Vec<_> = match args.get(0).map(|arg| &**arg) {
|
||||
Some("jit") => {
|
||||
env::set_var(
|
||||
"RUSTFLAGS",
|
||||
env::var("RUSTFLAGS").unwrap_or(String::new()) + " -Cprefer-dynamic",
|
||||
);
|
||||
rustflags.push("-Cprefer-dynamic".to_owned());
|
||||
args.remove(0);
|
||||
IntoIterator::into_iter(["rustc".to_string()])
|
||||
.chain(args)
|
||||
@ -64,10 +55,7 @@ fn main() {
|
||||
.collect()
|
||||
}
|
||||
Some("lazy-jit") => {
|
||||
env::set_var(
|
||||
"RUSTFLAGS",
|
||||
env::var("RUSTFLAGS").unwrap_or(String::new()) + " -Cprefer-dynamic",
|
||||
);
|
||||
rustflags.push("-Cprefer-dynamic".to_owned());
|
||||
args.remove(0);
|
||||
IntoIterator::into_iter(["rustc".to_string()])
|
||||
.chain(args)
|
||||
@ -81,11 +69,28 @@ fn main() {
|
||||
_ => args,
|
||||
};
|
||||
|
||||
let mut cmd = Command::new(cargo);
|
||||
cmd.args(args);
|
||||
rustflags_to_cmd_env(
|
||||
&mut cmd,
|
||||
"RUSTFLAGS",
|
||||
&rustflags_from_env("RUSTFLAGS")
|
||||
.into_iter()
|
||||
.chain(rustflags.iter().map(|flag| flag.clone()))
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
rustflags_to_cmd_env(
|
||||
&mut cmd,
|
||||
"RUSTDOCFLAGS",
|
||||
&rustflags_from_env("RUSTDOCFLAGS")
|
||||
.into_iter()
|
||||
.chain(rustflags.iter().map(|flag| flag.clone()))
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
|
||||
#[cfg(unix)]
|
||||
panic!("Failed to spawn cargo: {}", Command::new(cargo).args(args).exec());
|
||||
panic!("Failed to spawn cargo: {}", cmd.exec());
|
||||
|
||||
#[cfg(not(unix))]
|
||||
std::process::exit(
|
||||
Command::new(cargo).args(args).spawn().unwrap().wait().unwrap().code().unwrap_or(1),
|
||||
);
|
||||
std::process::exit(cmd.spawn().unwrap().wait().unwrap().code().unwrap_or(1));
|
||||
}
|
||||
|
@ -49,6 +49,8 @@ rm tests/ui/proc-macro/allowed-signatures.rs
|
||||
# vendor intrinsics
|
||||
rm tests/ui/sse2.rs # cpuid not supported, so sse2 not detected
|
||||
rm tests/ui/simd/array-type.rs # "Index argument for `simd_insert` is not a constant"
|
||||
rm tests/ui/simd/intrinsic/generic-bswap-byte.rs # simd_bswap not yet implemented
|
||||
rm tests/ui/simd/intrinsic/generic-arithmetic-pass.rs # many missing simd intrinsics
|
||||
|
||||
# exotic linkages
|
||||
rm tests/ui/issues/issue-33992.rs # unsupported linkages
|
||||
@ -124,6 +126,8 @@ rm tests/ui/typeck/issue-46112.rs # same
|
||||
rm tests/ui/consts/const_cmp_type_id.rs # same
|
||||
rm tests/ui/consts/issue-73976-monomorphic.rs # same
|
||||
rm tests/ui/rfcs/rfc-3348-c-string-literals/non-ascii.rs # same
|
||||
rm tests/ui/consts/const-eval/nonnull_as_ref_ub.rs # same
|
||||
rm tests/ui/consts/issue-94675.rs # same
|
||||
|
||||
# rustdoc-clif passes extra args, suppressing the help message when no args are passed
|
||||
rm -r tests/run-make/issue-88756-default-output
|
||||
@ -158,8 +162,6 @@ rm tests/ui/process/nofile-limit.rs # TODO some AArch64 linking issue
|
||||
|
||||
rm tests/ui/stdio-is-blocking.rs # really slow with unoptimized libstd
|
||||
|
||||
rm tests/ui/panic-handler/weak-lang-item-2.rs # Will be fixed by #113568
|
||||
|
||||
cp ../dist/bin/rustdoc-clif ../dist/bin/rustdoc # some tests expect bin/rustdoc to exist
|
||||
|
||||
# prevent $(RUSTDOC) from picking up the sysroot built by x.py. It conflicts with the one used by
|
||||
@ -172,7 +174,7 @@ index ea06b620c4c..b969d0009c6 100644
|
||||
@@ -9,7 +9,7 @@ RUSTC_ORIGINAL := \$(RUSTC)
|
||||
BARE_RUSTC := \$(HOST_RPATH_ENV) '\$(RUSTC)'
|
||||
BARE_RUSTDOC := \$(HOST_RPATH_ENV) '\$(RUSTDOC)'
|
||||
RUSTC := \$(BARE_RUSTC) --out-dir \$(TMPDIR) -L \$(TMPDIR) \$(RUSTFLAGS)
|
||||
RUSTC := \$(BARE_RUSTC) --out-dir \$(TMPDIR) -L \$(TMPDIR) \$(RUSTFLAGS) -Ainternal_features
|
||||
-RUSTDOC := \$(BARE_RUSTDOC) -L \$(TARGET_RPATH_DIR)
|
||||
+RUSTDOC := \$(BARE_RUSTDOC)
|
||||
ifdef RUSTC_LINKER
|
||||
|
@ -48,7 +48,9 @@ pub(crate) fn conv_to_call_conv(sess: &Session, c: Conv, default_call_conv: Call
|
||||
default_call_conv
|
||||
}
|
||||
|
||||
Conv::X86Intr => sess.fatal("x86-interrupt call conv not yet implemented"),
|
||||
Conv::X86Intr | Conv::RiscvInterrupt { .. } => {
|
||||
sess.fatal(format!("interrupt call conv {c:?} not yet implemented"))
|
||||
}
|
||||
|
||||
Conv::ArmAapcs => sess.fatal("aapcs call conv not yet implemented"),
|
||||
Conv::CCmseNonSecureCall => {
|
||||
|
@ -260,6 +260,13 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Arc<dyn isa::Tar
|
||||
flags_builder.set("enable_verifier", enable_verifier).unwrap();
|
||||
flags_builder.set("regalloc_checker", enable_verifier).unwrap();
|
||||
|
||||
let preserve_frame_pointer = sess.target.options.frame_pointer
|
||||
!= rustc_target::spec::FramePointer::MayOmit
|
||||
|| matches!(sess.opts.cg.force_frame_pointers, Some(true));
|
||||
if preserve_frame_pointer {
|
||||
flags_builder.set("preserve_frame_pointers", "true").unwrap();
|
||||
}
|
||||
|
||||
let tls_model = match target_triple.binary_format {
|
||||
BinaryFormat::Elf => "elf_gd",
|
||||
BinaryFormat::Macho => "macho",
|
||||
|
@ -383,13 +383,16 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
||||
}
|
||||
|
||||
fn apply_attrs_llfn(&self, cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value) {
|
||||
let mut func_attrs = SmallVec::<[_; 2]>::new();
|
||||
let mut func_attrs = SmallVec::<[_; 3]>::new();
|
||||
if self.ret.layout.abi.is_uninhabited() {
|
||||
func_attrs.push(llvm::AttributeKind::NoReturn.create_attr(cx.llcx));
|
||||
}
|
||||
if !self.can_unwind {
|
||||
func_attrs.push(llvm::AttributeKind::NoUnwind.create_attr(cx.llcx));
|
||||
}
|
||||
if let Conv::RiscvInterrupt { kind } = self.conv {
|
||||
func_attrs.push(llvm::CreateAttrStringValue(cx.llcx, "interrupt", kind.as_str()));
|
||||
}
|
||||
attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &{ func_attrs });
|
||||
|
||||
let mut i = 0;
|
||||
@ -565,7 +568,9 @@ impl<'tcx> AbiBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
|
||||
impl From<Conv> for llvm::CallConv {
|
||||
fn from(conv: Conv) -> Self {
|
||||
match conv {
|
||||
Conv::C | Conv::Rust | Conv::CCmseNonSecureCall => llvm::CCallConv,
|
||||
Conv::C | Conv::Rust | Conv::CCmseNonSecureCall | Conv::RiscvInterrupt { .. } => {
|
||||
llvm::CCallConv
|
||||
}
|
||||
Conv::RustCold => llvm::ColdCallConv,
|
||||
Conv::AmdGpuKernel => llvm::AmdGpuKernel,
|
||||
Conv::AvrInterrupt => llvm::AvrInterrupt,
|
||||
|
@ -320,6 +320,7 @@ impl<'a> DiagnosticHandlers<'a> {
|
||||
})
|
||||
.and_then(|dir| dir.to_str().and_then(|p| CString::new(p).ok()));
|
||||
|
||||
let pgo_available = cgcx.opts.cg.profile_use.is_some();
|
||||
let data = Box::into_raw(Box::new((cgcx, handler)));
|
||||
unsafe {
|
||||
let old_handler = llvm::LLVMRustContextGetDiagnosticHandler(llcx);
|
||||
@ -333,6 +334,7 @@ impl<'a> DiagnosticHandlers<'a> {
|
||||
// The `as_ref()` is important here, otherwise the `CString` will be dropped
|
||||
// too soon!
|
||||
remark_file.as_ref().map(|dir| dir.as_ptr()).unwrap_or(std::ptr::null()),
|
||||
pgo_available,
|
||||
);
|
||||
DiagnosticHandlers { data, llcx, old_handler }
|
||||
}
|
||||
@ -470,6 +472,8 @@ pub(crate) unsafe fn llvm_optimize(
|
||||
Some(llvm::SanitizerOptions {
|
||||
sanitize_address: config.sanitizer.contains(SanitizerSet::ADDRESS),
|
||||
sanitize_address_recover: config.sanitizer_recover.contains(SanitizerSet::ADDRESS),
|
||||
sanitize_cfi: config.sanitizer.contains(SanitizerSet::CFI),
|
||||
sanitize_kcfi: config.sanitizer.contains(SanitizerSet::KCFI),
|
||||
sanitize_memory: config.sanitizer.contains(SanitizerSet::MEMORY),
|
||||
sanitize_memory_recover: config.sanitizer_recover.contains(SanitizerSet::MEMORY),
|
||||
sanitize_memory_track_origins: config.sanitizer_memory_track_origins as c_int,
|
||||
@ -505,6 +509,7 @@ pub(crate) unsafe fn llvm_optimize(
|
||||
&*module.module_llvm.tm,
|
||||
to_pass_builder_opt_level(opt_level),
|
||||
opt_stage,
|
||||
cgcx.opts.cg.linker_plugin_lto.enabled(),
|
||||
config.no_prepopulate_passes,
|
||||
config.verify_llvm_ir,
|
||||
using_thin_buffers,
|
||||
|
@ -1512,9 +1512,9 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
|
||||
fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
|
||||
llfn: &'ll Value,
|
||||
) {
|
||||
let is_indirect_call = unsafe { llvm::LLVMIsAFunction(llfn).is_none() };
|
||||
if is_indirect_call && fn_abi.is_some() && self.tcx.sess.is_sanitizer_cfi_enabled() {
|
||||
if fn_attrs.is_some() && fn_attrs.unwrap().no_sanitize.contains(SanitizerSet::CFI) {
|
||||
let is_indirect_call = unsafe { llvm::LLVMRustIsNonGVFunctionPointerTy(llfn) };
|
||||
if self.tcx.sess.is_sanitizer_cfi_enabled() && let Some(fn_abi) = fn_abi && is_indirect_call {
|
||||
if let Some(fn_attrs) = fn_attrs && fn_attrs.no_sanitize.contains(SanitizerSet::CFI) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1526,7 +1526,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
|
||||
options.insert(TypeIdOptions::NORMALIZE_INTEGERS);
|
||||
}
|
||||
|
||||
let typeid = typeid_for_fnabi(self.tcx, fn_abi.unwrap(), options);
|
||||
let typeid = typeid_for_fnabi(self.tcx, fn_abi, options);
|
||||
let typeid_metadata = self.cx.typeid_metadata(typeid).unwrap();
|
||||
|
||||
// Test whether the function pointer is associated with the type identifier.
|
||||
@ -1550,25 +1550,26 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
|
||||
fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
|
||||
llfn: &'ll Value,
|
||||
) -> Option<llvm::OperandBundleDef<'ll>> {
|
||||
let is_indirect_call = unsafe { llvm::LLVMIsAFunction(llfn).is_none() };
|
||||
let kcfi_bundle = if is_indirect_call && self.tcx.sess.is_sanitizer_kcfi_enabled() {
|
||||
if fn_attrs.is_some() && fn_attrs.unwrap().no_sanitize.contains(SanitizerSet::KCFI) {
|
||||
return None;
|
||||
}
|
||||
let is_indirect_call = unsafe { llvm::LLVMRustIsNonGVFunctionPointerTy(llfn) };
|
||||
let kcfi_bundle =
|
||||
if self.tcx.sess.is_sanitizer_kcfi_enabled() && let Some(fn_abi) = fn_abi && is_indirect_call {
|
||||
if let Some(fn_attrs) = fn_attrs && fn_attrs.no_sanitize.contains(SanitizerSet::KCFI) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut options = TypeIdOptions::empty();
|
||||
if self.tcx.sess.is_sanitizer_cfi_generalize_pointers_enabled() {
|
||||
options.insert(TypeIdOptions::GENERALIZE_POINTERS);
|
||||
}
|
||||
if self.tcx.sess.is_sanitizer_cfi_normalize_integers_enabled() {
|
||||
options.insert(TypeIdOptions::NORMALIZE_INTEGERS);
|
||||
}
|
||||
let mut options = TypeIdOptions::empty();
|
||||
if self.tcx.sess.is_sanitizer_cfi_generalize_pointers_enabled() {
|
||||
options.insert(TypeIdOptions::GENERALIZE_POINTERS);
|
||||
}
|
||||
if self.tcx.sess.is_sanitizer_cfi_normalize_integers_enabled() {
|
||||
options.insert(TypeIdOptions::NORMALIZE_INTEGERS);
|
||||
}
|
||||
|
||||
let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi.unwrap(), options);
|
||||
Some(llvm::OperandBundleDef::new("kcfi", &[self.const_u32(kcfi_typeid)]))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi, options);
|
||||
Some(llvm::OperandBundleDef::new("kcfi", &[self.const_u32(kcfi_typeid)]))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
kcfi_bundle
|
||||
}
|
||||
}
|
||||
|
@ -475,6 +475,8 @@ pub enum OptStage {
|
||||
pub struct SanitizerOptions {
|
||||
pub sanitize_address: bool,
|
||||
pub sanitize_address_recover: bool,
|
||||
pub sanitize_cfi: bool,
|
||||
pub sanitize_kcfi: bool,
|
||||
pub sanitize_memory: bool,
|
||||
pub sanitize_memory_recover: bool,
|
||||
pub sanitize_memory_track_origins: c_int,
|
||||
@ -894,6 +896,7 @@ extern "C" {
|
||||
pub fn LLVMRustGlobalAddMetadata<'a>(Val: &'a Value, KindID: c_uint, Metadata: &'a Metadata);
|
||||
pub fn LLVMValueAsMetadata(Node: &Value) -> &Metadata;
|
||||
pub fn LLVMIsAFunction(Val: &Value) -> Option<&Value>;
|
||||
pub fn LLVMRustIsNonGVFunctionPointerTy(Val: &Value) -> bool;
|
||||
|
||||
// Operations on constants of any type
|
||||
pub fn LLVMConstNull(Ty: &Type) -> &Value;
|
||||
@ -2138,6 +2141,7 @@ extern "C" {
|
||||
TM: &'a TargetMachine,
|
||||
OptLevel: PassBuilderOptLevel,
|
||||
OptStage: OptStage,
|
||||
IsLinkerPluginLTO: bool,
|
||||
NoPrepopulatePasses: bool,
|
||||
VerifyIR: bool,
|
||||
UseThinLTOBuffers: bool,
|
||||
@ -2332,6 +2336,7 @@ extern "C" {
|
||||
remark_passes: *const *const c_char,
|
||||
remark_passes_len: usize,
|
||||
remark_file: *const c_char,
|
||||
pgo_available: bool,
|
||||
);
|
||||
|
||||
#[allow(improper_ctypes)]
|
||||
|
@ -13,6 +13,7 @@ use std::{env, mem, str};
|
||||
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
||||
use rustc_metadata::find_native_static_library;
|
||||
use rustc_middle::middle::dependency_format::Linkage;
|
||||
use rustc_middle::middle::exported_symbols;
|
||||
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo, SymbolExportKind};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip};
|
||||
@ -659,8 +660,6 @@ impl<'a> Linker for GccLinker<'a> {
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME(#99978) hide #[no_mangle] symbols for proc-macros
|
||||
|
||||
let is_windows = self.sess.target.is_like_windows;
|
||||
let path = tmpdir.join(if is_windows { "list.def" } else { "list" });
|
||||
|
||||
@ -1679,8 +1678,15 @@ pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<St
|
||||
return exports.iter().map(ToString::to_string).collect();
|
||||
}
|
||||
|
||||
let mut symbols = Vec::new();
|
||||
if let CrateType::ProcMacro = crate_type {
|
||||
exported_symbols_for_proc_macro_crate(tcx)
|
||||
} else {
|
||||
exported_symbols_for_non_proc_macro(tcx, crate_type)
|
||||
}
|
||||
}
|
||||
|
||||
fn exported_symbols_for_non_proc_macro(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> {
|
||||
let mut symbols = Vec::new();
|
||||
let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
|
||||
for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| {
|
||||
if info.level.is_below_threshold(export_threshold) {
|
||||
@ -1691,6 +1697,19 @@ pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<St
|
||||
symbols
|
||||
}
|
||||
|
||||
fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<String> {
|
||||
// `exported_symbols` will be empty when !should_codegen.
|
||||
if !tcx.sess.opts.output_types.should_codegen() {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
let stable_crate_id = tcx.sess.local_stable_crate_id();
|
||||
let proc_macro_decls_name = tcx.sess.generate_proc_macro_decls_symbol(stable_crate_id);
|
||||
let metadata_symbol_name = exported_symbols::metadata_symbol_name(tcx);
|
||||
|
||||
vec![proc_macro_decls_name, metadata_symbol_name]
|
||||
}
|
||||
|
||||
pub(crate) fn linked_symbols(
|
||||
tcx: TyCtxt<'_>,
|
||||
crate_type: CrateType,
|
||||
|
@ -303,8 +303,6 @@ const_eval_remainder_overflow =
|
||||
overflow in signed remainder (dividing MIN by -1)
|
||||
const_eval_scalar_size_mismatch =
|
||||
scalar size mismatch: expected {$target_size} bytes but got {$data_size} bytes instead
|
||||
const_eval_size_of_unsized =
|
||||
size_of called on unsized type `{$ty}`
|
||||
const_eval_size_overflow =
|
||||
overflow computing total size of `{$name}`
|
||||
|
||||
|
@ -40,7 +40,7 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness {
|
||||
| hir::Node::AnonConst(_)
|
||||
| hir::Node::ConstBlock(_)
|
||||
| hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) => hir::Constness::Const,
|
||||
hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) => impl_.constness,
|
||||
hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(_), .. }) => tcx.generics_of(def_id).host_effect_index.map_or(hir::Constness::NotConst, |_| hir::Constness::Const),
|
||||
hir::Node::ForeignItem(hir::ForeignItem { kind: hir::ForeignItemKind::Fn(..), .. }) => {
|
||||
// Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other
|
||||
// foreign items cannot be evaluated at compile-time.
|
||||
|
@ -7,9 +7,10 @@ use crate::interpret::{
|
||||
intern_const_alloc_recursive, ConstValue, ImmTy, Immediate, InternKind, MemPlaceMeta,
|
||||
MemoryKind, Place, Projectable, Scalar,
|
||||
};
|
||||
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
|
||||
use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
|
||||
use rustc_span::source_map::DUMMY_SP;
|
||||
use rustc_target::abi::{Align, FieldIdx, VariantIdx, FIRST_VARIANT};
|
||||
use rustc_target::abi::VariantIdx;
|
||||
|
||||
#[instrument(skip(ecx), level = "debug")]
|
||||
fn branches<'tcx>(
|
||||
@ -154,52 +155,37 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip(ecx), level = "debug")]
|
||||
fn create_mplace_from_layout<'tcx>(
|
||||
ecx: &mut CompileTimeEvalContext<'tcx, 'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> MPlaceTy<'tcx> {
|
||||
let tcx = ecx.tcx;
|
||||
let param_env = ecx.param_env;
|
||||
let layout = tcx.layout_of(param_env.and(ty)).unwrap();
|
||||
debug!(?layout);
|
||||
|
||||
ecx.allocate(layout, MemoryKind::Stack).unwrap()
|
||||
}
|
||||
|
||||
// Walks custom DSTs and gets the type of the unsized field and the number of elements
|
||||
// in the unsized field.
|
||||
fn get_info_on_unsized_field<'tcx>(
|
||||
ty: Ty<'tcx>,
|
||||
/// Valtrees don't store the `MemPlaceMeta` that all dynamically sized values have in the interpreter.
|
||||
/// This function reconstructs it.
|
||||
fn reconstruct_place_meta<'tcx>(
|
||||
layout: TyAndLayout<'tcx>,
|
||||
valtree: ty::ValTree<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> (Ty<'tcx>, usize) {
|
||||
) -> MemPlaceMeta {
|
||||
if layout.is_sized() {
|
||||
return MemPlaceMeta::None;
|
||||
}
|
||||
|
||||
let mut last_valtree = valtree;
|
||||
// Traverse the type, and update `last_valtree` as we go.
|
||||
let tail = tcx.struct_tail_with_normalize(
|
||||
ty,
|
||||
layout.ty,
|
||||
|ty| ty,
|
||||
|| {
|
||||
let branches = last_valtree.unwrap_branch();
|
||||
last_valtree = branches[branches.len() - 1];
|
||||
last_valtree = *branches.last().unwrap();
|
||||
debug!(?branches, ?last_valtree);
|
||||
},
|
||||
);
|
||||
let unsized_inner_ty = match tail.kind() {
|
||||
ty::Slice(t) => *t,
|
||||
ty::Str => tail,
|
||||
_ => bug!("expected Slice or Str"),
|
||||
// Sanity-check that we got a tail we support.
|
||||
match tail.kind() {
|
||||
ty::Slice(..) | ty::Str => {}
|
||||
_ => bug!("unsized tail of a valtree must be Slice or Str"),
|
||||
};
|
||||
|
||||
// Have to adjust type for ty::Str
|
||||
let unsized_inner_ty = match unsized_inner_ty.kind() {
|
||||
ty::Str => tcx.types.u8,
|
||||
_ => unsized_inner_ty,
|
||||
};
|
||||
|
||||
// Get the number of elements in the unsized field
|
||||
// Get the number of elements in the unsized field.
|
||||
let num_elems = last_valtree.unwrap_branch().len();
|
||||
|
||||
(unsized_inner_ty, num_elems)
|
||||
MemPlaceMeta::Meta(Scalar::from_target_usize(num_elems as u64, &tcx))
|
||||
}
|
||||
|
||||
#[instrument(skip(ecx), level = "debug", ret)]
|
||||
@ -208,41 +194,9 @@ fn create_pointee_place<'tcx>(
|
||||
ty: Ty<'tcx>,
|
||||
valtree: ty::ValTree<'tcx>,
|
||||
) -> MPlaceTy<'tcx> {
|
||||
let tcx = ecx.tcx.tcx;
|
||||
|
||||
if !ty.is_sized(*ecx.tcx, ty::ParamEnv::empty()) {
|
||||
// We need to create `Allocation`s for custom DSTs
|
||||
|
||||
let (unsized_inner_ty, num_elems) = get_info_on_unsized_field(ty, valtree, tcx);
|
||||
let unsized_inner_ty = match unsized_inner_ty.kind() {
|
||||
ty::Str => tcx.types.u8,
|
||||
_ => unsized_inner_ty,
|
||||
};
|
||||
let unsized_inner_ty_size =
|
||||
tcx.layout_of(ty::ParamEnv::empty().and(unsized_inner_ty)).unwrap().layout.size();
|
||||
debug!(?unsized_inner_ty, ?unsized_inner_ty_size, ?num_elems);
|
||||
|
||||
// for custom DSTs only the last field/element is unsized, but we need to also allocate
|
||||
// space for the other fields/elements
|
||||
let layout = tcx.layout_of(ty::ParamEnv::empty().and(ty)).unwrap();
|
||||
let size_of_sized_part = layout.layout.size();
|
||||
|
||||
// Get the size of the memory behind the DST
|
||||
let dst_size = unsized_inner_ty_size.checked_mul(num_elems as u64, &tcx).unwrap();
|
||||
|
||||
let size = size_of_sized_part.checked_add(dst_size, &tcx).unwrap();
|
||||
let align = Align::from_bytes(size.bytes().next_power_of_two()).unwrap();
|
||||
let ptr = ecx.allocate_ptr(size, align, MemoryKind::Stack).unwrap();
|
||||
debug!(?ptr);
|
||||
|
||||
MPlaceTy::from_aligned_ptr_with_meta(
|
||||
ptr.into(),
|
||||
layout,
|
||||
MemPlaceMeta::Meta(Scalar::from_target_usize(num_elems as u64, &tcx)),
|
||||
)
|
||||
} else {
|
||||
create_mplace_from_layout(ecx, ty)
|
||||
}
|
||||
let layout = ecx.layout_of(ty).unwrap();
|
||||
let meta = reconstruct_place_meta(layout, valtree, ecx.tcx.tcx);
|
||||
ecx.allocate_dyn(layout, MemoryKind::Stack, meta).unwrap()
|
||||
}
|
||||
|
||||
/// Converts a `ValTree` to a `ConstValue`, which is needed after mir
|
||||
@ -282,10 +236,13 @@ pub fn valtree_to_const_value<'tcx>(
|
||||
ty::Ref(_, _, _) | ty::Tuple(_) | ty::Array(_, _) | ty::Adt(..) => {
|
||||
let place = match ty.kind() {
|
||||
ty::Ref(_, inner_ty, _) => {
|
||||
// Need to create a place for the pointee to fill for Refs
|
||||
// Need to create a place for the pointee (the reference itself will be an immediate)
|
||||
create_pointee_place(&mut ecx, *inner_ty, valtree)
|
||||
}
|
||||
_ => create_mplace_from_layout(&mut ecx, ty),
|
||||
_ => {
|
||||
// Need to create a place for this valtree.
|
||||
create_pointee_place(&mut ecx, ty, valtree)
|
||||
}
|
||||
};
|
||||
debug!(?place);
|
||||
|
||||
@ -399,45 +356,8 @@ fn valtree_into_mplace<'tcx>(
|
||||
debug!(?i, ?inner_valtree);
|
||||
|
||||
let place_inner = match ty.kind() {
|
||||
ty::Str | ty::Slice(_) => ecx.project_index(place, i as u64).unwrap(),
|
||||
_ if !ty.is_sized(*ecx.tcx, ty::ParamEnv::empty())
|
||||
&& i == branches.len() - 1 =>
|
||||
{
|
||||
// Note: For custom DSTs we need to manually process the last unsized field.
|
||||
// We created a `Pointer` for the `Allocation` of the complete sized version of
|
||||
// the Adt in `create_pointee_place` and now we fill that `Allocation` with the
|
||||
// values in the ValTree. For the unsized field we have to additionally add the meta
|
||||
// data.
|
||||
|
||||
let (unsized_inner_ty, num_elems) =
|
||||
get_info_on_unsized_field(ty, valtree, tcx);
|
||||
debug!(?unsized_inner_ty);
|
||||
|
||||
let inner_ty = match ty.kind() {
|
||||
ty::Adt(def, args) => {
|
||||
let i = FieldIdx::from_usize(i);
|
||||
def.variant(FIRST_VARIANT).fields[i].ty(tcx, args)
|
||||
}
|
||||
ty::Tuple(inner_tys) => inner_tys[i],
|
||||
_ => bug!("unexpected unsized type {:?}", ty),
|
||||
};
|
||||
|
||||
let inner_layout =
|
||||
tcx.layout_of(ty::ParamEnv::empty().and(inner_ty)).unwrap();
|
||||
debug!(?inner_layout);
|
||||
|
||||
let offset = place_adjusted.layout.fields.offset(i);
|
||||
place
|
||||
.offset_with_meta(
|
||||
offset,
|
||||
MemPlaceMeta::Meta(Scalar::from_target_usize(
|
||||
num_elems as u64,
|
||||
&tcx,
|
||||
)),
|
||||
inner_layout,
|
||||
&tcx,
|
||||
)
|
||||
.unwrap()
|
||||
ty::Str | ty::Slice(_) | ty::Array(..) => {
|
||||
ecx.project_index(place, i as u64).unwrap()
|
||||
}
|
||||
_ => ecx.project_field(&place_adjusted, i).unwrap(),
|
||||
};
|
||||
|
@ -862,7 +862,6 @@ impl<'tcx> ReportErrorExt for InvalidProgramInfo<'tcx> {
|
||||
InvalidProgramInfo::FnAbiAdjustForForeignAbi(_) => {
|
||||
rustc_middle::error::middle_adjust_for_foreign_abi_error
|
||||
}
|
||||
InvalidProgramInfo::SizeOfUnsizedType(_) => const_eval_size_of_unsized,
|
||||
InvalidProgramInfo::ConstPropNonsense => {
|
||||
panic!("We had const-prop nonsense, this should never be printed")
|
||||
}
|
||||
@ -890,9 +889,6 @@ impl<'tcx> ReportErrorExt for InvalidProgramInfo<'tcx> {
|
||||
builder.set_arg("arch", arch);
|
||||
builder.set_arg("abi", abi.name());
|
||||
}
|
||||
InvalidProgramInfo::SizeOfUnsizedType(ty) => {
|
||||
builder.set_arg("ty", ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -934,14 +934,26 @@ where
|
||||
Ok(MPlaceTy { mplace, layout: place.layout, align: place.align })
|
||||
}
|
||||
|
||||
pub fn allocate_dyn(
|
||||
&mut self,
|
||||
layout: TyAndLayout<'tcx>,
|
||||
kind: MemoryKind<M::MemoryKind>,
|
||||
meta: MemPlaceMeta<M::Provenance>,
|
||||
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
|
||||
let Some((size, align)) = self.size_and_align_of(&meta, &layout)? else {
|
||||
span_bug!(self.cur_span(), "cannot allocate space for `extern` type, size is not known")
|
||||
};
|
||||
let ptr = self.allocate_ptr(size, align, kind)?;
|
||||
Ok(MPlaceTy::from_aligned_ptr_with_meta(ptr.into(), layout, meta))
|
||||
}
|
||||
|
||||
pub fn allocate(
|
||||
&mut self,
|
||||
layout: TyAndLayout<'tcx>,
|
||||
kind: MemoryKind<M::MemoryKind>,
|
||||
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
|
||||
assert!(layout.is_sized());
|
||||
let ptr = self.allocate_ptr(layout.size, layout.align.abi, kind)?;
|
||||
Ok(MPlaceTy::from_aligned_ptr(ptr.into(), layout))
|
||||
self.allocate_dyn(layout, kind, MemPlaceMeta::None)
|
||||
}
|
||||
|
||||
/// Returns a wide MPlace of type `&'static [mut] str` to a new 1-aligned allocation.
|
||||
|
@ -269,13 +269,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty)?;
|
||||
let layout = self.layout_of(ty)?;
|
||||
if let mir::NullOp::SizeOf | mir::NullOp::AlignOf = null_op && layout.is_unsized() {
|
||||
// FIXME: This should be a span_bug, but const generics can run MIR
|
||||
// that is not properly type-checked yet (#97477).
|
||||
self.tcx.sess.delay_span_bug(
|
||||
span_bug!(
|
||||
self.frame().current_span(),
|
||||
format!("{null_op:?} MIR operator called for unsized type {ty}"),
|
||||
"{null_op:?} MIR operator called for unsized type {ty}",
|
||||
);
|
||||
throw_inval!(SizeOfUnsizedType(ty));
|
||||
}
|
||||
let val = match null_op {
|
||||
mir::NullOp::SizeOf => layout.size.bytes(),
|
||||
|
@ -393,15 +393,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
));
|
||||
assert_eq!(dest_offset, None);
|
||||
// Allocate enough memory to hold `src`.
|
||||
let Some((size, align)) = self.size_and_align_of_mplace(&src)? else {
|
||||
span_bug!(
|
||||
self.cur_span(),
|
||||
"unsized fn arg with `extern` type tail should not be allowed"
|
||||
)
|
||||
};
|
||||
let ptr = self.allocate_ptr(size, align, MemoryKind::Stack)?;
|
||||
let dest_place =
|
||||
MPlaceTy::from_aligned_ptr_with_meta(ptr.into(), callee_arg.layout, src.meta);
|
||||
let dest_place = self.allocate_dyn(src.layout, MemoryKind::Stack, src.meta)?;
|
||||
// Update the local to be that new place.
|
||||
*M::access_local_mut(self, dest_frame, dest_local)? = Operand::Indirect(*dest_place);
|
||||
}
|
||||
|
@ -127,15 +127,8 @@ fn is_parent_const_stable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||
let hir_id = tcx.local_def_id_to_hir_id(local_def_id);
|
||||
|
||||
let Some(parent) = tcx.hir().opt_parent_id(hir_id) else { return false };
|
||||
let parent_def = tcx.hir().get(parent);
|
||||
|
||||
if !matches!(
|
||||
parent_def,
|
||||
hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Impl(hir::Impl { constness: hir::Constness::Const, .. }),
|
||||
..
|
||||
})
|
||||
) {
|
||||
if !tcx.is_const_trait_impl_raw(parent.owner.def_id.to_def_id()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -145,8 +145,11 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
|
||||
let implsrc = selcx.select(&obligation);
|
||||
|
||||
if let Ok(Some(ImplSource::UserDefined(data))) = implsrc {
|
||||
let span = tcx.def_span(data.impl_def_id);
|
||||
err.subdiagnostic(errors::NonConstImplNote { span });
|
||||
// FIXME(effects) revisit this
|
||||
if !tcx.is_const_trait_impl_raw(data.impl_def_id) {
|
||||
let span = tcx.def_span(data.impl_def_id);
|
||||
err.subdiagnostic(errors::NonConstImplNote { span });
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
@ -30,7 +30,10 @@ pub fn push_str(mut n: u128, base: usize, output: &mut String) {
|
||||
}
|
||||
}
|
||||
|
||||
output.push_str(str::from_utf8(&s[index..]).unwrap());
|
||||
output.push_str(unsafe {
|
||||
// SAFETY: `s` is populated using only valid utf8 characters from `BASE_64`
|
||||
str::from_utf8_unchecked(&s[index..])
|
||||
});
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -32,7 +32,7 @@ use rustc_feature::find_gated_cfg;
|
||||
use rustc_fluent_macro::fluent_messages;
|
||||
use rustc_interface::util::{self, collect_crate_types, get_codegen_backend};
|
||||
use rustc_interface::{interface, Queries};
|
||||
use rustc_lint::LintStore;
|
||||
use rustc_lint::{unerased_lint_store, LintStore};
|
||||
use rustc_metadata::locator;
|
||||
use rustc_session::config::{nightly_options, CG_OPTIONS, Z_OPTIONS};
|
||||
use rustc_session::config::{ErrorOutputType, Input, OutFileName, OutputType, TrimmedDefPaths};
|
||||
@ -411,15 +411,11 @@ fn run_compiler(
|
||||
return early_exit();
|
||||
}
|
||||
|
||||
{
|
||||
let plugins = queries.register_plugins()?;
|
||||
let (.., lint_store) = &*plugins.borrow();
|
||||
|
||||
// Lint plugins are registered; now we can process command line flags.
|
||||
if sess.opts.describe_lints {
|
||||
describe_lints(sess, lint_store, true);
|
||||
return early_exit();
|
||||
}
|
||||
if sess.opts.describe_lints {
|
||||
queries
|
||||
.global_ctxt()?
|
||||
.enter(|tcx| describe_lints(sess, unerased_lint_store(tcx), true));
|
||||
return early_exit();
|
||||
}
|
||||
|
||||
// Make sure name resolution and macro expansion is run.
|
||||
|
@ -313,6 +313,8 @@ declare_features! (
|
||||
(active, abi_msp430_interrupt, "1.16.0", Some(38487), None),
|
||||
/// Allows `extern "ptx-*" fn()`.
|
||||
(active, abi_ptx, "1.15.0", Some(38788), None),
|
||||
/// Allows `extern "riscv-interrupt-m" fn()` and `extern "riscv-interrupt-s" fn()`.
|
||||
(active, abi_riscv_interrupt, "CURRENT_RUSTC_VERSION", Some(111889), None),
|
||||
/// Allows `extern "x86-interrupt" fn()`.
|
||||
(active, abi_x86_interrupt, "1.17.0", Some(40180), None),
|
||||
/// Allows additional const parameter types, such as `&'static str` or user defined types
|
||||
|
@ -2675,7 +2675,7 @@ pub struct OpaqueTy<'hir> {
|
||||
///
|
||||
/// This mapping associated a captured lifetime (first parameter) with the new
|
||||
/// early-bound lifetime that was generated for the opaque.
|
||||
pub lifetime_mapping: Option<&'hir [(&'hir Lifetime, LocalDefId)]>,
|
||||
pub lifetime_mapping: &'hir [(&'hir Lifetime, LocalDefId)],
|
||||
/// Whether the opaque is a return-position impl trait (or async future)
|
||||
/// originating from a trait method. This makes it so that the opaque is
|
||||
/// lowered as an associated type.
|
||||
@ -3359,7 +3359,6 @@ pub struct Impl<'hir> {
|
||||
// We do not put a `Span` in `Defaultness` because it breaks foreign crate metadata
|
||||
// decoding as `Span`s cannot be decoded when a `Session` is not available.
|
||||
pub defaultness_span: Option<Span>,
|
||||
pub constness: Constness,
|
||||
pub generics: &'hir Generics<'hir>,
|
||||
|
||||
/// The trait being implemented, if any.
|
||||
|
@ -522,7 +522,6 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) {
|
||||
unsafety: _,
|
||||
defaultness: _,
|
||||
polarity: _,
|
||||
constness: _,
|
||||
defaultness_span: _,
|
||||
ref generics,
|
||||
ref of_trait,
|
||||
|
@ -532,6 +532,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
if let Err(guar) = ty.error_reported() {
|
||||
return ty::Const::new_error(tcx, guar, ty).into();
|
||||
}
|
||||
// FIXME(effects) see if we should special case effect params here
|
||||
if !infer_args && has_default {
|
||||
tcx.const_param_default(param.def_id)
|
||||
.instantiate(tcx, args.unwrap())
|
||||
@ -659,7 +660,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
&self,
|
||||
trait_ref: &hir::TraitRef<'_>,
|
||||
self_ty: Ty<'tcx>,
|
||||
constness: ty::BoundConstness,
|
||||
) -> ty::TraitRef<'tcx> {
|
||||
self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
|
||||
|
||||
@ -669,7 +669,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
self_ty,
|
||||
trait_ref.path.segments.last().unwrap(),
|
||||
true,
|
||||
constness,
|
||||
ty::BoundConstness::NotConst,
|
||||
)
|
||||
}
|
||||
|
||||
@ -849,6 +849,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
self_ty: Ty<'tcx>,
|
||||
trait_segment: &hir::PathSegment<'_>,
|
||||
is_impl: bool,
|
||||
// FIXME(effects) move all host param things in astconv to hir lowering
|
||||
constness: ty::BoundConstness,
|
||||
) -> ty::TraitRef<'tcx> {
|
||||
let (generic_args, _) = self.create_args_for_ast_trait_ref(
|
||||
@ -2714,11 +2715,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
};
|
||||
let i = hir.get_parent(fn_hir_id).expect_item().expect_impl();
|
||||
|
||||
let trait_ref = self.instantiate_mono_trait_ref(
|
||||
i.of_trait.as_ref()?,
|
||||
self.ast_ty_to_ty(i.self_ty),
|
||||
ty::BoundConstness::NotConst,
|
||||
);
|
||||
let trait_ref =
|
||||
self.instantiate_mono_trait_ref(i.of_trait.as_ref()?, self.ast_ty_to_ty(i.self_ty));
|
||||
|
||||
let assoc = tcx.associated_items(trait_ref.def_id).find_by_name_and_kind(
|
||||
tcx,
|
||||
|
@ -407,7 +407,17 @@ fn check_opaque_meets_bounds<'tcx>(
|
||||
.build();
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
|
||||
let args = GenericArgs::identity_for_item(tcx, def_id.to_def_id());
|
||||
let args = match *origin {
|
||||
hir::OpaqueTyOrigin::FnReturn(parent) | hir::OpaqueTyOrigin::AsyncFn(parent) => {
|
||||
GenericArgs::identity_for_item(tcx, parent).extend_to(
|
||||
tcx,
|
||||
def_id.to_def_id(),
|
||||
|param, _| tcx.map_rpit_lifetime_to_fn_lifetime(param.def_id.expect_local()).into(),
|
||||
)
|
||||
}
|
||||
hir::OpaqueTyOrigin::TyAlias { .. } => GenericArgs::identity_for_item(tcx, def_id),
|
||||
};
|
||||
|
||||
let opaque_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args);
|
||||
|
||||
// `ReErased` regions appear in the "parent_args" of closures/generators.
|
||||
@ -468,9 +478,10 @@ fn check_opaque_meets_bounds<'tcx>(
|
||||
}
|
||||
}
|
||||
// Check that any hidden types found during wf checking match the hidden types that `type_of` sees.
|
||||
for (key, mut ty) in infcx.take_opaque_types() {
|
||||
for (mut key, mut ty) in infcx.take_opaque_types() {
|
||||
ty.hidden_type.ty = infcx.resolve_vars_if_possible(ty.hidden_type.ty);
|
||||
sanity_check_found_hidden_type(tcx, key, ty.hidden_type, defining_use_anchor, origin)?;
|
||||
key = infcx.resolve_vars_if_possible(key);
|
||||
sanity_check_found_hidden_type(tcx, key, ty.hidden_type)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -479,8 +490,6 @@ fn sanity_check_found_hidden_type<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
key: ty::OpaqueTypeKey<'tcx>,
|
||||
mut ty: ty::OpaqueHiddenType<'tcx>,
|
||||
defining_use_anchor: LocalDefId,
|
||||
origin: &hir::OpaqueTyOrigin,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
if ty.ty.is_ty_var() {
|
||||
// Nothing was actually constrained.
|
||||
@ -493,29 +502,23 @@ fn sanity_check_found_hidden_type<'tcx>(
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
let strip_vars = |ty: Ty<'tcx>| {
|
||||
ty.fold_with(&mut BottomUpFolder {
|
||||
tcx,
|
||||
ty_op: |t| t,
|
||||
ct_op: |c| c,
|
||||
lt_op: |l| match l.kind() {
|
||||
RegionKind::ReVar(_) => tcx.lifetimes.re_erased,
|
||||
_ => l,
|
||||
},
|
||||
})
|
||||
};
|
||||
// Closures frequently end up containing erased lifetimes in their final representation.
|
||||
// These correspond to lifetime variables that never got resolved, so we patch this up here.
|
||||
ty.ty = ty.ty.fold_with(&mut BottomUpFolder {
|
||||
tcx,
|
||||
ty_op: |t| t,
|
||||
ct_op: |c| c,
|
||||
lt_op: |l| match l.kind() {
|
||||
RegionKind::ReVar(_) => tcx.lifetimes.re_erased,
|
||||
_ => l,
|
||||
},
|
||||
});
|
||||
ty.ty = strip_vars(ty.ty);
|
||||
// Get the hidden type.
|
||||
let mut hidden_ty = tcx.type_of(key.def_id).instantiate(tcx, key.args);
|
||||
if let hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) = origin {
|
||||
if hidden_ty != ty.ty {
|
||||
hidden_ty = find_and_apply_rpit_args(
|
||||
tcx,
|
||||
hidden_ty,
|
||||
defining_use_anchor.to_def_id(),
|
||||
key.def_id.to_def_id(),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
let hidden_ty = tcx.type_of(key.def_id).instantiate(tcx, key.args);
|
||||
let hidden_ty = strip_vars(hidden_ty);
|
||||
|
||||
// If the hidden types differ, emit a type mismatch diagnostic.
|
||||
if hidden_ty == ty.ty {
|
||||
@ -527,105 +530,6 @@ fn sanity_check_found_hidden_type<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
/// In case it is in a nested opaque type, find that opaque type's
|
||||
/// usage in the function signature and use the generic arguments from the usage site.
|
||||
/// We need to do because RPITs ignore the lifetimes of the function,
|
||||
/// as they have their own copies of all the lifetimes they capture.
|
||||
/// So the only way to get the lifetimes represented in terms of the function,
|
||||
/// is to look how they are used in the function signature (or do some other fancy
|
||||
/// recording of this mapping at ast -> hir lowering time).
|
||||
///
|
||||
/// As an example:
|
||||
/// ```text
|
||||
/// trait Id {
|
||||
/// type Assoc;
|
||||
/// }
|
||||
/// impl<'a> Id for &'a () {
|
||||
/// type Assoc = &'a ();
|
||||
/// }
|
||||
/// fn func<'a>(x: &'a ()) -> impl Id<Assoc = impl Sized + 'a> { x }
|
||||
/// // desugared to
|
||||
/// fn func<'a>(x: &'a () -> Outer<'a> where <Outer<'a> as Id>::Assoc = Inner<'a> {
|
||||
/// // Note that in contrast to other nested items, RPIT type aliases can
|
||||
/// // access their parents' generics.
|
||||
///
|
||||
/// // hidden type is `&'aDupOuter ()`
|
||||
/// // During wfcheck the hidden type of `Inner<'aDupOuter>` is `&'a ()`, but
|
||||
/// // `typeof(Inner<'aDupOuter>) = &'aDupOuter ()`.
|
||||
/// // So we walk the signature of `func` to find the use of `Inner<'a>`
|
||||
/// // and then use that to replace the lifetimes in the hidden type, obtaining
|
||||
/// // `&'a ()`.
|
||||
/// type Outer<'aDupOuter> = impl Id<Assoc = Inner<'aDupOuter>>;
|
||||
///
|
||||
/// // hidden type is `&'aDupInner ()`
|
||||
/// type Inner<'aDupInner> = impl Sized + 'aDupInner;
|
||||
///
|
||||
/// x
|
||||
/// }
|
||||
/// ```
|
||||
fn find_and_apply_rpit_args<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
mut hidden_ty: Ty<'tcx>,
|
||||
function: DefId,
|
||||
opaque: DefId,
|
||||
) -> Result<Ty<'tcx>, ErrorGuaranteed> {
|
||||
// Find use of the RPIT in the function signature and thus find the right args to
|
||||
// convert it into the parameter space of the function signature. This is needed,
|
||||
// because that's what `type_of` returns, against which we compare later.
|
||||
let ret = tcx.fn_sig(function).instantiate_identity().output();
|
||||
struct Visitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
opaque: DefId,
|
||||
seen: FxHashSet<DefId>,
|
||||
}
|
||||
impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for Visitor<'tcx> {
|
||||
type BreakTy = GenericArgsRef<'tcx>;
|
||||
|
||||
#[instrument(level = "trace", skip(self), ret)]
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
trace!("{:#?}", t.kind());
|
||||
match t.kind() {
|
||||
ty::Alias(ty::Opaque, alias) => {
|
||||
trace!(?alias.def_id);
|
||||
if alias.def_id == self.opaque {
|
||||
return ControlFlow::Break(alias.args);
|
||||
} else if self.seen.insert(alias.def_id) {
|
||||
for clause in self
|
||||
.tcx
|
||||
.explicit_item_bounds(alias.def_id)
|
||||
.iter_instantiated_copied(self.tcx, alias.args)
|
||||
{
|
||||
trace!(?clause);
|
||||
clause.visit_with(self)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
ty::Alias(ty::Weak, alias) => {
|
||||
self.tcx
|
||||
.type_of(alias.def_id)
|
||||
.instantiate(self.tcx, alias.args)
|
||||
.visit_with(self)?;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
t.super_visit_with(self)
|
||||
}
|
||||
}
|
||||
if let ControlFlow::Break(args) =
|
||||
ret.visit_with(&mut Visitor { tcx, opaque, seen: Default::default() })
|
||||
{
|
||||
trace!(?args);
|
||||
trace!("expected: {hidden_ty:#?}");
|
||||
hidden_ty = ty::EarlyBinder::bind(hidden_ty).instantiate(tcx, args);
|
||||
trace!("expected: {hidden_ty:#?}");
|
||||
} else {
|
||||
tcx.sess
|
||||
.delay_span_bug(tcx.def_span(function), format!("{ret:?} does not contain {opaque:?}"));
|
||||
}
|
||||
Ok(hidden_ty)
|
||||
}
|
||||
|
||||
fn is_enum_of_nonnullable_ptr<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
adt_def: AdtDef<'tcx>,
|
||||
|
@ -1359,38 +1359,60 @@ fn impl_trait_ref(
|
||||
.as_ref()
|
||||
.map(|ast_trait_ref| {
|
||||
let selfty = tcx.type_of(def_id).instantiate_identity();
|
||||
icx.astconv().instantiate_mono_trait_ref(
|
||||
ast_trait_ref,
|
||||
selfty,
|
||||
check_impl_constness(tcx, impl_.constness, ast_trait_ref),
|
||||
)
|
||||
|
||||
if let Some(ErrorGuaranteed { .. }) = check_impl_constness(
|
||||
tcx,
|
||||
tcx.is_const_trait_impl_raw(def_id.to_def_id()),
|
||||
&ast_trait_ref,
|
||||
) {
|
||||
// we have a const impl, but for a trait without `#[const_trait]`, so
|
||||
// without the host param. If we continue with the HIR trait ref, we get
|
||||
// ICEs for generic arg count mismatch. We do a little HIR editing to
|
||||
// make astconv happy.
|
||||
let mut path_segments = ast_trait_ref.path.segments.to_vec();
|
||||
let last_segment = path_segments.len() - 1;
|
||||
let mut args = path_segments[last_segment].args().clone();
|
||||
let last_arg = args.args.len() - 1;
|
||||
assert!(matches!(args.args[last_arg], hir::GenericArg::Const(anon_const) if tcx.has_attr(anon_const.value.def_id, sym::rustc_host)));
|
||||
args.args = &args.args[..args.args.len() - 1];
|
||||
path_segments[last_segment].args = Some(&args);
|
||||
let path = hir::Path {
|
||||
span: ast_trait_ref.path.span,
|
||||
res: ast_trait_ref.path.res,
|
||||
segments: &path_segments,
|
||||
};
|
||||
let trait_ref = hir::TraitRef { path: &path, hir_ref_id: ast_trait_ref.hir_ref_id };
|
||||
icx.astconv().instantiate_mono_trait_ref(&trait_ref, selfty)
|
||||
} else {
|
||||
icx.astconv().instantiate_mono_trait_ref(&ast_trait_ref, selfty)
|
||||
}
|
||||
})
|
||||
.map(ty::EarlyBinder::bind)
|
||||
}
|
||||
|
||||
fn check_impl_constness(
|
||||
tcx: TyCtxt<'_>,
|
||||
constness: hir::Constness,
|
||||
is_const: bool,
|
||||
ast_trait_ref: &hir::TraitRef<'_>,
|
||||
) -> ty::BoundConstness {
|
||||
match constness {
|
||||
hir::Constness::Const => {
|
||||
if let Some(trait_def_id) = ast_trait_ref.trait_def_id() && !tcx.has_attr(trait_def_id, sym::const_trait) {
|
||||
let trait_name = tcx.item_name(trait_def_id).to_string();
|
||||
tcx.sess.emit_err(errors::ConstImplForNonConstTrait {
|
||||
trait_ref_span: ast_trait_ref.path.span,
|
||||
trait_name,
|
||||
local_trait_span: trait_def_id.as_local().map(|_| tcx.def_span(trait_def_id).shrink_to_lo()),
|
||||
marking: (),
|
||||
adding: (),
|
||||
});
|
||||
ty::BoundConstness::NotConst
|
||||
} else {
|
||||
ty::BoundConstness::ConstIfConst
|
||||
}
|
||||
},
|
||||
hir::Constness::NotConst => ty::BoundConstness::NotConst,
|
||||
) -> Option<ErrorGuaranteed> {
|
||||
if !is_const {
|
||||
return None;
|
||||
}
|
||||
|
||||
let trait_def_id = ast_trait_ref.trait_def_id()?;
|
||||
if tcx.has_attr(trait_def_id, sym::const_trait) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let trait_name = tcx.item_name(trait_def_id).to_string();
|
||||
Some(tcx.sess.emit_err(errors::ConstImplForNonConstTrait {
|
||||
trait_ref_span: ast_trait_ref.path.span,
|
||||
trait_name,
|
||||
local_trait_span:
|
||||
trait_def_id.as_local().map(|_| tcx.def_span(trait_def_id).shrink_to_lo()),
|
||||
marking: (),
|
||||
adding: (),
|
||||
}))
|
||||
}
|
||||
|
||||
fn impl_polarity(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::ImplPolarity {
|
||||
|
@ -320,7 +320,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
||||
bug!("parent also has host effect param? index: {idx}, def: {def_id:?}");
|
||||
}
|
||||
|
||||
host_effect_index = Some(parent_count + index as usize);
|
||||
host_effect_index = Some(index as usize);
|
||||
}
|
||||
|
||||
Some(ty::GenericParamDef {
|
||||
|
@ -2,16 +2,16 @@ use crate::astconv::{AstConv, OnlySelfBounds, PredicateFilter};
|
||||
use crate::bounds::Bounds;
|
||||
use crate::collect::ItemCtxt;
|
||||
use crate::constrained_generic_params as cgp;
|
||||
use hir::{HirId, Lifetime, Node};
|
||||
use hir::{HirId, Node};
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{GenericPredicates, Generics, ImplTraitInTraitData, ToPredicate};
|
||||
use rustc_middle::ty::{GenericPredicates, ImplTraitInTraitData, ToPredicate};
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::{Span, Symbol, DUMMY_SP};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
||||
/// Returns a list of all type predicates (explicit and implicit) for the definition with
|
||||
/// ID `def_id`. This includes all predicates returned by `predicates_defined_on`, plus
|
||||
@ -55,17 +55,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
||||
use rustc_hir::*;
|
||||
|
||||
match tcx.opt_rpitit_info(def_id.to_def_id()) {
|
||||
Some(ImplTraitInTraitData::Trait { opaque_def_id, fn_def_id }) => {
|
||||
let opaque_ty_id = tcx.hir().local_def_id_to_hir_id(opaque_def_id.expect_local());
|
||||
let opaque_ty_node = tcx.hir().get(opaque_ty_id);
|
||||
let Node::Item(&Item {
|
||||
kind: ItemKind::OpaqueTy(OpaqueTy { lifetime_mapping: Some(lifetime_mapping), .. }),
|
||||
..
|
||||
}) = opaque_ty_node
|
||||
else {
|
||||
bug!("unexpected {opaque_ty_node:?}")
|
||||
};
|
||||
|
||||
Some(ImplTraitInTraitData::Trait { fn_def_id, .. }) => {
|
||||
let mut predicates = Vec::new();
|
||||
|
||||
// RPITITs should inherit the predicates of their parent. This is
|
||||
@ -78,13 +68,12 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
||||
|
||||
// We also install bidirectional outlives predicates for the RPITIT
|
||||
// to keep the duplicates lifetimes from opaque lowering in sync.
|
||||
// We only need to compute bidirectional outlives for the duplicated
|
||||
// opaque lifetimes, which explains the slicing below.
|
||||
compute_bidirectional_outlives_predicates(
|
||||
tcx,
|
||||
def_id,
|
||||
lifetime_mapping.iter().map(|(lifetime, def_id)| {
|
||||
(**lifetime, (*def_id, lifetime.ident.name, lifetime.ident.span))
|
||||
}),
|
||||
tcx.generics_of(def_id.to_def_id()),
|
||||
&tcx.generics_of(def_id.to_def_id()).params
|
||||
[tcx.generics_of(fn_def_id).params.len()..],
|
||||
&mut predicates,
|
||||
);
|
||||
|
||||
@ -351,21 +340,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
||||
};
|
||||
debug!(?lifetimes);
|
||||
|
||||
let lifetime_mapping = std::iter::zip(lifetimes, ast_generics.params)
|
||||
.map(|(arg, dup)| {
|
||||
let hir::GenericArg::Lifetime(arg) = arg else { bug!() };
|
||||
(**arg, dup)
|
||||
})
|
||||
.filter(|(_, dup)| matches!(dup.kind, hir::GenericParamKind::Lifetime { .. }))
|
||||
.map(|(lifetime, dup)| (lifetime, (dup.def_id, dup.name.ident().name, dup.span)));
|
||||
|
||||
compute_bidirectional_outlives_predicates(
|
||||
tcx,
|
||||
def_id,
|
||||
lifetime_mapping,
|
||||
generics,
|
||||
&mut predicates,
|
||||
);
|
||||
compute_bidirectional_outlives_predicates(tcx, &generics.params, &mut predicates);
|
||||
debug!(?predicates);
|
||||
}
|
||||
|
||||
@ -379,41 +354,28 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
||||
/// enforce that these lifetimes stay in sync.
|
||||
fn compute_bidirectional_outlives_predicates<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
item_def_id: LocalDefId,
|
||||
lifetime_mapping: impl Iterator<Item = (Lifetime, (LocalDefId, Symbol, Span))>,
|
||||
generics: &Generics,
|
||||
opaque_own_params: &[ty::GenericParamDef],
|
||||
predicates: &mut Vec<(ty::Clause<'tcx>, Span)>,
|
||||
) {
|
||||
let icx = ItemCtxt::new(tcx, item_def_id);
|
||||
|
||||
for (arg, (dup_def, name, span)) in lifetime_mapping {
|
||||
let orig_region = icx.astconv().ast_region_to_region(&arg, None);
|
||||
if !matches!(orig_region.kind(), ty::ReEarlyBound(..)) {
|
||||
// There is no late-bound lifetime to actually match up here, since the lifetime doesn't
|
||||
// show up in the opaque's parent's args.
|
||||
continue;
|
||||
for param in opaque_own_params {
|
||||
let orig_lifetime = tcx.map_rpit_lifetime_to_fn_lifetime(param.def_id.expect_local());
|
||||
if let ty::ReEarlyBound(..) = *orig_lifetime {
|
||||
let dup_lifetime = ty::Region::new_early_bound(
|
||||
tcx,
|
||||
ty::EarlyBoundRegion { def_id: param.def_id, index: param.index, name: param.name },
|
||||
);
|
||||
let span = tcx.def_span(param.def_id);
|
||||
predicates.push((
|
||||
ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(orig_lifetime, dup_lifetime))
|
||||
.to_predicate(tcx),
|
||||
span,
|
||||
));
|
||||
predicates.push((
|
||||
ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(dup_lifetime, orig_lifetime))
|
||||
.to_predicate(tcx),
|
||||
span,
|
||||
));
|
||||
}
|
||||
|
||||
let Some(dup_index) = generics.param_def_id_to_index(icx.tcx, dup_def.to_def_id()) else {
|
||||
bug!()
|
||||
};
|
||||
|
||||
let dup_region = ty::Region::new_early_bound(
|
||||
tcx,
|
||||
ty::EarlyBoundRegion { def_id: dup_def.to_def_id(), index: dup_index, name },
|
||||
);
|
||||
|
||||
predicates.push((
|
||||
ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(orig_region, dup_region))
|
||||
.to_predicate(tcx),
|
||||
span,
|
||||
));
|
||||
|
||||
predicates.push((
|
||||
ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(dup_region, orig_region))
|
||||
.to_predicate(tcx),
|
||||
span,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -578,6 +578,9 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
|
||||
MissingTypesOrConsts { .. } => {
|
||||
self.suggest_adding_type_and_const_args(err);
|
||||
}
|
||||
ExcessTypesOrConsts { .. } => {
|
||||
// this can happen with `~const T` where T isn't a const_trait.
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
@ -626,7 +626,6 @@ impl<'a> State<'a> {
|
||||
unsafety,
|
||||
polarity,
|
||||
defaultness,
|
||||
constness,
|
||||
defaultness_span: _,
|
||||
generics,
|
||||
ref of_trait,
|
||||
@ -643,10 +642,6 @@ impl<'a> State<'a> {
|
||||
self.space();
|
||||
}
|
||||
|
||||
if constness == hir::Constness::Const {
|
||||
self.word_nbsp("const");
|
||||
}
|
||||
|
||||
if let hir::ImplPolarity::Negative(_) = polarity {
|
||||
self.word("!");
|
||||
}
|
||||
|
@ -767,9 +767,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
) {
|
||||
let tcx = self.tcx;
|
||||
|
||||
if !tcx.features().effects || tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you {
|
||||
return;
|
||||
}
|
||||
// fast-reject if callee doesn't have the host effect param (non-const)
|
||||
let generics = tcx.generics_of(callee_did);
|
||||
let Some(host_effect_index) = generics.host_effect_index else { return };
|
||||
|
||||
// if the callee does have the param, we need to equate the param to some const
|
||||
// value no matter whether the effects feature is enabled in the local crate,
|
||||
// because inference will fail if we don't.
|
||||
let mut host_always_on =
|
||||
!tcx.features().effects || tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you;
|
||||
|
||||
// Compute the constness required by the context.
|
||||
let context = tcx.hir().enclosing_body_owner(call_expr_hir);
|
||||
@ -780,10 +786,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
if tcx.has_attr(context.to_def_id(), sym::rustc_do_not_const_check) {
|
||||
trace!("do not const check this context");
|
||||
return;
|
||||
host_always_on = true;
|
||||
}
|
||||
|
||||
let effect = match const_context {
|
||||
_ if host_always_on => tcx.consts.true_,
|
||||
Some(hir::ConstContext::Static(_) | hir::ConstContext::Const) => tcx.consts.false_,
|
||||
Some(hir::ConstContext::ConstFn) => {
|
||||
let args = ty::GenericArgs::identity_for_item(tcx, context);
|
||||
@ -792,21 +799,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
None => tcx.consts.true_,
|
||||
};
|
||||
|
||||
let generics = tcx.generics_of(callee_did);
|
||||
|
||||
trace!(?effect, ?generics, ?callee_args);
|
||||
|
||||
if let Some(idx) = generics.host_effect_index {
|
||||
let param = callee_args.const_at(idx);
|
||||
let cause = self.misc(span);
|
||||
match self.at(&cause, self.param_env).eq(infer::DefineOpaqueTypes::No, effect, param) {
|
||||
Ok(infer::InferOk { obligations, value: () }) => {
|
||||
self.register_predicates(obligations);
|
||||
}
|
||||
Err(e) => {
|
||||
// FIXME(effects): better diagnostic
|
||||
self.err_ctxt().report_mismatched_consts(&cause, effect, param, e).emit();
|
||||
}
|
||||
let param = callee_args.const_at(host_effect_index);
|
||||
let cause = self.misc(span);
|
||||
match self.at(&cause, self.param_env).eq(infer::DefineOpaqueTypes::No, effect, param) {
|
||||
Ok(infer::InferOk { obligations, value: () }) => {
|
||||
self.register_predicates(obligations);
|
||||
}
|
||||
Err(e) => {
|
||||
// FIXME(effects): better diagnostic
|
||||
self.err_ctxt().report_mismatched_consts(&cause, effect, param, e).emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1007,15 +1007,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
&self,
|
||||
expr: &hir::Expr<'_>,
|
||||
expr_ty: Ty<'tcx>,
|
||||
target: Ty<'tcx>,
|
||||
mut target: Ty<'tcx>,
|
||||
allow_two_phase: AllowTwoPhase,
|
||||
cause: Option<ObligationCause<'tcx>>,
|
||||
) -> RelateResult<'tcx, Ty<'tcx>> {
|
||||
let source = self.try_structurally_resolve_type(expr.span, expr_ty);
|
||||
let target = self.try_structurally_resolve_type(
|
||||
cause.as_ref().map_or(expr.span, |cause| cause.span),
|
||||
target,
|
||||
);
|
||||
if self.next_trait_solver() {
|
||||
target = self.try_structurally_resolve_type(
|
||||
cause.as_ref().map_or(expr.span, |cause| cause.span),
|
||||
target,
|
||||
);
|
||||
}
|
||||
debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target);
|
||||
|
||||
let cause =
|
||||
|
@ -13,7 +13,7 @@ use crate::errors::{
|
||||
YieldExprOutsideOfGenerator,
|
||||
};
|
||||
use crate::fatally_break_rust;
|
||||
use crate::method::SelfSource;
|
||||
use crate::method::{MethodCallComponents, SelfSource};
|
||||
use crate::type_error_struct;
|
||||
use crate::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation};
|
||||
use crate::{
|
||||
@ -1281,7 +1281,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
segment.ident,
|
||||
SelfSource::MethodCall(rcvr),
|
||||
error,
|
||||
Some((rcvr, args)),
|
||||
Some(MethodCallComponents { receiver: rcvr, args, full_expr: expr }),
|
||||
expected,
|
||||
false,
|
||||
) {
|
||||
|
@ -1349,7 +1349,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
GenericParamDefKind::Const { has_default } => {
|
||||
if !infer_args && has_default {
|
||||
if !infer_args
|
||||
&& has_default
|
||||
&& !tcx.has_attr(param.def_id, sym::rustc_host)
|
||||
{
|
||||
tcx.const_param_default(param.def_id)
|
||||
.instantiate(tcx, args.unwrap())
|
||||
.into()
|
||||
|
@ -7,7 +7,7 @@ mod prelude2021;
|
||||
pub mod probe;
|
||||
mod suggest;
|
||||
|
||||
pub use self::suggest::SelfSource;
|
||||
pub use self::suggest::{MethodCallComponents, SelfSource};
|
||||
pub use self::MethodError::*;
|
||||
|
||||
use crate::errors::OpMethodGenericParams;
|
||||
|
@ -50,6 +50,15 @@ use rustc_hir::intravisit::Visitor;
|
||||
use std::cmp::{self, Ordering};
|
||||
use std::iter;
|
||||
|
||||
/// After identifying that `full_expr` is a method call, we use this type to keep the expression's
|
||||
/// components readily available to us to point at the right place in diagnostics.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct MethodCallComponents<'tcx> {
|
||||
pub receiver: &'tcx hir::Expr<'tcx>,
|
||||
pub args: &'tcx [hir::Expr<'tcx>],
|
||||
pub full_expr: &'tcx hir::Expr<'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
|
||||
let tcx = self.tcx;
|
||||
@ -115,7 +124,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
item_name: Ident,
|
||||
source: SelfSource<'tcx>,
|
||||
error: MethodError<'tcx>,
|
||||
args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
|
||||
args: Option<MethodCallComponents<'tcx>>,
|
||||
expected: Expectation<'tcx>,
|
||||
trait_missing_method: bool,
|
||||
) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> {
|
||||
@ -257,18 +266,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
fn suggest_missing_writer(
|
||||
&self,
|
||||
rcvr_ty: Ty<'tcx>,
|
||||
args: (&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>]),
|
||||
args: MethodCallComponents<'tcx>,
|
||||
) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
|
||||
let (ty_str, _ty_file) = self.tcx.short_ty_string(rcvr_ty);
|
||||
let mut err =
|
||||
struct_span_err!(self.tcx.sess, args.0.span, E0599, "cannot write into `{}`", ty_str);
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
args.receiver.span,
|
||||
E0599,
|
||||
"cannot write into `{}`",
|
||||
ty_str
|
||||
);
|
||||
err.span_note(
|
||||
args.0.span,
|
||||
args.receiver.span,
|
||||
"must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method",
|
||||
);
|
||||
if let ExprKind::Lit(_) = args.0.kind {
|
||||
if let ExprKind::Lit(_) = args.receiver.kind {
|
||||
err.span_help(
|
||||
args.0.span.shrink_to_lo(),
|
||||
args.receiver.span.shrink_to_lo(),
|
||||
"a writer is needed before this format string",
|
||||
);
|
||||
};
|
||||
@ -282,7 +296,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
rcvr_ty: Ty<'tcx>,
|
||||
item_name: Ident,
|
||||
source: SelfSource<'tcx>,
|
||||
args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
|
||||
args: Option<MethodCallComponents<'tcx>>,
|
||||
sugg_span: Span,
|
||||
no_match_data: &mut NoMatchData<'tcx>,
|
||||
expected: Expectation<'tcx>,
|
||||
@ -953,6 +967,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
unsatisfied_bounds = true;
|
||||
}
|
||||
} else if let ty::Adt(def, targs) = rcvr_ty.kind() && let Some(args) = args {
|
||||
// This is useful for methods on arbitrary self types that might have a simple
|
||||
// mutability difference, like calling a method on `Pin<&mut Self>` that is on
|
||||
// `Pin<&Self>`.
|
||||
if targs.len() == 1 {
|
||||
let mut item_segment = hir::PathSegment::invalid();
|
||||
item_segment.ident = item_name;
|
||||
for t in [Ty::new_mut_ref, Ty::new_imm_ref, |_, _, t| t] {
|
||||
let new_args = tcx.mk_args_from_iter(
|
||||
targs
|
||||
.iter()
|
||||
.map(|arg| match arg.as_type() {
|
||||
Some(ty) => ty::GenericArg::from(
|
||||
t(tcx, tcx.lifetimes.re_erased, ty.peel_refs()),
|
||||
),
|
||||
_ => arg,
|
||||
})
|
||||
);
|
||||
let rcvr_ty = Ty::new_adt(tcx, *def, new_args);
|
||||
if let Ok(method) = self.lookup_method_for_diagnostic(
|
||||
rcvr_ty,
|
||||
&item_segment,
|
||||
span,
|
||||
args.full_expr,
|
||||
args.receiver,
|
||||
) {
|
||||
err.span_note(
|
||||
tcx.def_span(method.def_id),
|
||||
format!("{item_kind} is available for `{rcvr_ty}`"),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let label_span_not_found = |err: &mut Diagnostic| {
|
||||
@ -1111,7 +1158,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
span,
|
||||
rcvr_ty,
|
||||
item_name,
|
||||
args.map(|(_, args)| args.len() + 1),
|
||||
args.map(|MethodCallComponents { args, .. }| args.len() + 1),
|
||||
source,
|
||||
no_match_data.out_of_scope_traits.clone(),
|
||||
&unsatisfied_predicates,
|
||||
@ -1192,7 +1239,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
&self,
|
||||
rcvr_ty: Ty<'tcx>,
|
||||
item_name: Ident,
|
||||
args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
|
||||
args: Option<MethodCallComponents<'tcx>>,
|
||||
span: Span,
|
||||
err: &mut Diagnostic,
|
||||
sources: &mut Vec<CandidateSource>,
|
||||
@ -1343,7 +1390,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
rcvr_ty: Ty<'tcx>,
|
||||
source: SelfSource<'tcx>,
|
||||
item_name: Ident,
|
||||
args: Option<(&hir::Expr<'tcx>, &[hir::Expr<'tcx>])>,
|
||||
args: Option<MethodCallComponents<'tcx>>,
|
||||
sugg_span: Span,
|
||||
) {
|
||||
let mut has_unsuggestable_args = false;
|
||||
@ -1415,7 +1462,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
None
|
||||
};
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let args = if let Some((receiver, args)) = args {
|
||||
let args = if let Some(MethodCallComponents { receiver, args, .. }) = args {
|
||||
// The first arg is the same kind as the receiver
|
||||
let explicit_args = if first_arg.is_some() {
|
||||
std::iter::once(receiver).chain(args.iter()).collect::<Vec<_>>()
|
||||
@ -2995,7 +3042,7 @@ pub fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> {
|
||||
|
||||
fn print_disambiguation_help<'tcx>(
|
||||
item_name: Ident,
|
||||
args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
|
||||
args: Option<MethodCallComponents<'tcx>>,
|
||||
err: &mut Diagnostic,
|
||||
trait_name: String,
|
||||
rcvr_ty: Ty<'_>,
|
||||
@ -3007,7 +3054,11 @@ fn print_disambiguation_help<'tcx>(
|
||||
fn_has_self_parameter: bool,
|
||||
) {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let (span, sugg) = if let (ty::AssocKind::Fn, Some((receiver, args))) = (kind, args) {
|
||||
let (span, sugg) = if let (
|
||||
ty::AssocKind::Fn,
|
||||
Some(MethodCallComponents { receiver, args, .. }),
|
||||
) = (kind, args)
|
||||
{
|
||||
let args = format!(
|
||||
"({}{})",
|
||||
rcvr_ty.ref_mutability().map_or("", |mutbl| mutbl.ref_prefix_str()),
|
||||
|
@ -12,7 +12,7 @@ use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal};
|
||||
use rustc_errors::PResult;
|
||||
use rustc_expand::base::{ExtCtxt, LintStoreExpand};
|
||||
use rustc_fs_util::try_canonicalize;
|
||||
use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE};
|
||||
use rustc_hir::def_id::LOCAL_CRATE;
|
||||
use rustc_lint::{unerased_lint_store, BufferedEarlyLint, EarlyCheckNode, LintStore};
|
||||
use rustc_metadata::creader::CStore;
|
||||
use rustc_middle::arena::Arena;
|
||||
@ -72,43 +72,16 @@ fn count_nodes(krate: &ast::Crate) -> usize {
|
||||
counter.count
|
||||
}
|
||||
|
||||
pub fn register_plugins<'a>(
|
||||
sess: &'a Session,
|
||||
metadata_loader: &'a dyn MetadataLoader,
|
||||
register_lints: impl Fn(&Session, &mut LintStore),
|
||||
pub(crate) fn create_lint_store(
|
||||
sess: &Session,
|
||||
metadata_loader: &dyn MetadataLoader,
|
||||
register_lints: Option<impl Fn(&Session, &mut LintStore)>,
|
||||
pre_configured_attrs: &[ast::Attribute],
|
||||
crate_name: Symbol,
|
||||
) -> Result<LintStore> {
|
||||
// these need to be set "early" so that expansion sees `quote` if enabled.
|
||||
let features = rustc_expand::config::features(sess, pre_configured_attrs);
|
||||
sess.init_features(features);
|
||||
|
||||
let crate_types = util::collect_crate_types(sess, pre_configured_attrs);
|
||||
sess.init_crate_types(crate_types);
|
||||
|
||||
let stable_crate_id = StableCrateId::new(
|
||||
crate_name,
|
||||
sess.crate_types().contains(&CrateType::Executable),
|
||||
sess.opts.cg.metadata.clone(),
|
||||
sess.cfg_version,
|
||||
);
|
||||
sess.stable_crate_id.set(stable_crate_id).expect("not yet initialized");
|
||||
rustc_incremental::prepare_session_directory(sess, crate_name, stable_crate_id)?;
|
||||
|
||||
if sess.opts.incremental.is_some() {
|
||||
sess.time("incr_comp_garbage_collect_session_directories", || {
|
||||
if let Err(e) = rustc_incremental::garbage_collect_session_directories(sess) {
|
||||
warn!(
|
||||
"Error while trying to garbage collect incremental \
|
||||
compilation cache directory: {}",
|
||||
e
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
) -> LintStore {
|
||||
let mut lint_store = rustc_lint::new_lint_store(sess.enable_internal_lints());
|
||||
register_lints(sess, &mut lint_store);
|
||||
if let Some(register_lints) = register_lints {
|
||||
register_lints(sess, &mut lint_store);
|
||||
}
|
||||
|
||||
let registrars = sess.time("plugin_loading", || {
|
||||
plugin::load::load_plugins(sess, metadata_loader, pre_configured_attrs)
|
||||
@ -120,7 +93,7 @@ pub fn register_plugins<'a>(
|
||||
}
|
||||
});
|
||||
|
||||
Ok(lint_store)
|
||||
lint_store
|
||||
}
|
||||
|
||||
fn pre_expansion_lint<'a>(
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::errors::{FailedWritingFile, RustcErrorFatal, RustcErrorUnexpectedAnnotation};
|
||||
use crate::interface::{Compiler, Result};
|
||||
use crate::passes;
|
||||
use crate::{passes, util};
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_codegen_ssa::traits::CodegenBackend;
|
||||
@ -9,15 +9,14 @@ use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::steal::Steal;
|
||||
use rustc_data_structures::svh::Svh;
|
||||
use rustc_data_structures::sync::{AppendOnlyIndexVec, Lrc, OnceCell, RwLock, WorkerLocal};
|
||||
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE};
|
||||
use rustc_hir::def_id::{StableCrateId, CRATE_DEF_ID, LOCAL_CRATE};
|
||||
use rustc_hir::definitions::Definitions;
|
||||
use rustc_incremental::DepGraphFuture;
|
||||
use rustc_lint::LintStore;
|
||||
use rustc_metadata::creader::CStore;
|
||||
use rustc_middle::arena::Arena;
|
||||
use rustc_middle::dep_graph::DepGraph;
|
||||
use rustc_middle::ty::{GlobalCtxt, TyCtxt};
|
||||
use rustc_session::config::{self, OutputFilenames, OutputType};
|
||||
use rustc_session::config::{self, CrateType, OutputFilenames, OutputType};
|
||||
use rustc_session::cstore::Untracked;
|
||||
use rustc_session::{output::find_crate_name, Session};
|
||||
use rustc_span::symbol::sym;
|
||||
@ -85,12 +84,11 @@ pub struct Queries<'tcx> {
|
||||
arena: WorkerLocal<Arena<'tcx>>,
|
||||
hir_arena: WorkerLocal<rustc_hir::Arena<'tcx>>,
|
||||
|
||||
dep_graph_future: Query<Option<DepGraphFuture>>,
|
||||
parse: Query<ast::Crate>,
|
||||
pre_configure: Query<(ast::Crate, ast::AttrVec)>,
|
||||
crate_name: Query<Symbol>,
|
||||
register_plugins: Query<(ast::Crate, ast::AttrVec, Lrc<LintStore>)>,
|
||||
dep_graph: Query<DepGraph>,
|
||||
crate_types: Query<Vec<CrateType>>,
|
||||
stable_crate_id: Query<StableCrateId>,
|
||||
// This just points to what's in `gcx_cell`.
|
||||
gcx: Query<&'tcx GlobalCtxt<'tcx>>,
|
||||
}
|
||||
@ -102,12 +100,11 @@ impl<'tcx> Queries<'tcx> {
|
||||
gcx_cell: OnceCell::new(),
|
||||
arena: WorkerLocal::new(|_| Arena::default()),
|
||||
hir_arena: WorkerLocal::new(|_| rustc_hir::Arena::default()),
|
||||
dep_graph_future: Default::default(),
|
||||
parse: Default::default(),
|
||||
pre_configure: Default::default(),
|
||||
crate_name: Default::default(),
|
||||
register_plugins: Default::default(),
|
||||
dep_graph: Default::default(),
|
||||
crate_types: Default::default(),
|
||||
stable_crate_id: Default::default(),
|
||||
gcx: Default::default(),
|
||||
}
|
||||
}
|
||||
@ -119,13 +116,6 @@ impl<'tcx> Queries<'tcx> {
|
||||
self.compiler.codegen_backend()
|
||||
}
|
||||
|
||||
fn dep_graph_future(&self) -> Result<QueryResult<'_, Option<DepGraphFuture>>> {
|
||||
self.dep_graph_future.compute(|| {
|
||||
let sess = self.session();
|
||||
Ok(sess.opts.build_dep_graph().then(|| rustc_incremental::load_dep_graph(sess)))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse(&self) -> Result<QueryResult<'_, ast::Crate>> {
|
||||
self.parse
|
||||
.compute(|| passes::parse(self.session()).map_err(|mut parse_error| parse_error.emit()))
|
||||
@ -148,84 +138,111 @@ impl<'tcx> Queries<'tcx> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn register_plugins(
|
||||
&self,
|
||||
) -> Result<QueryResult<'_, (ast::Crate, ast::AttrVec, Lrc<LintStore>)>> {
|
||||
self.register_plugins.compute(|| {
|
||||
let crate_name = *self.crate_name()?.borrow();
|
||||
let (krate, pre_configured_attrs) = self.pre_configure()?.steal();
|
||||
|
||||
let empty: &(dyn Fn(&Session, &mut LintStore) + Sync + Send) = &|_, _| {};
|
||||
let lint_store = passes::register_plugins(
|
||||
self.session(),
|
||||
&*self.codegen_backend().metadata_loader(),
|
||||
self.compiler.register_lints.as_deref().unwrap_or_else(|| empty),
|
||||
&pre_configured_attrs,
|
||||
crate_name,
|
||||
)?;
|
||||
|
||||
// Compute the dependency graph (in the background). We want to do
|
||||
// this as early as possible, to give the DepGraph maximum time to
|
||||
// load before dep_graph() is called, but it also can't happen
|
||||
// until after rustc_incremental::prepare_session_directory() is
|
||||
// called, which happens within passes::register_plugins().
|
||||
self.dep_graph_future().ok();
|
||||
|
||||
Ok((krate, pre_configured_attrs, Lrc::new(lint_store)))
|
||||
})
|
||||
}
|
||||
|
||||
fn crate_name(&self) -> Result<QueryResult<'_, Symbol>> {
|
||||
self.crate_name.compute(|| {
|
||||
Ok({
|
||||
let pre_configure_result = self.pre_configure()?;
|
||||
let (_, pre_configured_attrs) = &*pre_configure_result.borrow();
|
||||
// parse `#[crate_name]` even if `--crate-name` was passed, to make sure it matches.
|
||||
find_crate_name(self.session(), pre_configured_attrs)
|
||||
})
|
||||
let pre_configure_result = self.pre_configure()?;
|
||||
let (_, pre_configured_attrs) = &*pre_configure_result.borrow();
|
||||
// parse `#[crate_name]` even if `--crate-name` was passed, to make sure it matches.
|
||||
Ok(find_crate_name(self.session(), pre_configured_attrs))
|
||||
})
|
||||
}
|
||||
|
||||
fn dep_graph(&self) -> Result<QueryResult<'_, DepGraph>> {
|
||||
self.dep_graph.compute(|| {
|
||||
let sess = self.session();
|
||||
let future_opt = self.dep_graph_future()?.steal();
|
||||
let dep_graph = future_opt
|
||||
.and_then(|future| {
|
||||
let (prev_graph, mut prev_work_products) =
|
||||
sess.time("blocked_on_dep_graph_loading", || future.open().open(sess));
|
||||
// Convert from UnordMap to FxIndexMap by sorting
|
||||
let prev_work_product_ids =
|
||||
prev_work_products.items().map(|x| *x.0).into_sorted_stable_ord();
|
||||
let prev_work_products = prev_work_product_ids
|
||||
.into_iter()
|
||||
.map(|x| (x, prev_work_products.remove(&x).unwrap()))
|
||||
.collect::<FxIndexMap<_, _>>();
|
||||
rustc_incremental::build_dep_graph(sess, prev_graph, prev_work_products)
|
||||
})
|
||||
.unwrap_or_else(DepGraph::new_disabled);
|
||||
Ok(dep_graph)
|
||||
fn crate_types(&self) -> Result<QueryResult<'_, Vec<CrateType>>> {
|
||||
self.crate_types.compute(|| {
|
||||
let pre_configure_result = self.pre_configure()?;
|
||||
let (_, pre_configured_attrs) = &*pre_configure_result.borrow();
|
||||
Ok(util::collect_crate_types(&self.session(), &pre_configured_attrs))
|
||||
})
|
||||
}
|
||||
|
||||
fn stable_crate_id(&self) -> Result<QueryResult<'_, StableCrateId>> {
|
||||
self.stable_crate_id.compute(|| {
|
||||
let sess = self.session();
|
||||
Ok(StableCrateId::new(
|
||||
*self.crate_name()?.borrow(),
|
||||
self.crate_types()?.borrow().contains(&CrateType::Executable),
|
||||
sess.opts.cg.metadata.clone(),
|
||||
sess.cfg_version,
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
fn dep_graph_future(&self) -> Result<Option<DepGraphFuture>> {
|
||||
let sess = self.session();
|
||||
let crate_name = *self.crate_name()?.borrow();
|
||||
let stable_crate_id = *self.stable_crate_id()?.borrow();
|
||||
|
||||
// `load_dep_graph` can only be called after `prepare_session_directory`.
|
||||
rustc_incremental::prepare_session_directory(sess, crate_name, stable_crate_id)?;
|
||||
let res = sess.opts.build_dep_graph().then(|| rustc_incremental::load_dep_graph(sess));
|
||||
|
||||
if sess.opts.incremental.is_some() {
|
||||
sess.time("incr_comp_garbage_collect_session_directories", || {
|
||||
if let Err(e) = rustc_incremental::garbage_collect_session_directories(sess) {
|
||||
warn!(
|
||||
"Error while trying to garbage collect incremental \
|
||||
compilation cache directory: {}",
|
||||
e
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn dep_graph(&self, dep_graph_future: Option<DepGraphFuture>) -> DepGraph {
|
||||
dep_graph_future
|
||||
.and_then(|future| {
|
||||
let sess = self.session();
|
||||
let (prev_graph, mut prev_work_products) =
|
||||
sess.time("blocked_on_dep_graph_loading", || future.open().open(sess));
|
||||
// Convert from UnordMap to FxIndexMap by sorting
|
||||
let prev_work_product_ids =
|
||||
prev_work_products.items().map(|x| *x.0).into_sorted_stable_ord();
|
||||
let prev_work_products = prev_work_product_ids
|
||||
.into_iter()
|
||||
.map(|x| (x, prev_work_products.remove(&x).unwrap()))
|
||||
.collect::<FxIndexMap<_, _>>();
|
||||
rustc_incremental::build_dep_graph(sess, prev_graph, prev_work_products)
|
||||
})
|
||||
.unwrap_or_else(DepGraph::new_disabled)
|
||||
}
|
||||
|
||||
pub fn global_ctxt(&'tcx self) -> Result<QueryResult<'_, &'tcx GlobalCtxt<'tcx>>> {
|
||||
self.gcx.compute(|| {
|
||||
let crate_name = *self.crate_name()?.borrow();
|
||||
let (krate, pre_configured_attrs, lint_store) = self.register_plugins()?.steal();
|
||||
// Compute the dependency graph (in the background). We want to do this as early as
|
||||
// possible, to give the DepGraph maximum time to load before `dep_graph` is called.
|
||||
let dep_graph_future = self.dep_graph_future()?;
|
||||
|
||||
let crate_name = self.crate_name()?.steal();
|
||||
let crate_types = self.crate_types()?.steal();
|
||||
let stable_crate_id = self.stable_crate_id()?.steal();
|
||||
let (krate, pre_configured_attrs) = self.pre_configure()?.steal();
|
||||
|
||||
let sess = self.session();
|
||||
|
||||
let cstore = RwLock::new(Box::new(CStore::new(sess)) as _);
|
||||
let definitions = RwLock::new(Definitions::new(sess.local_stable_crate_id()));
|
||||
let lint_store = Lrc::new(passes::create_lint_store(
|
||||
sess,
|
||||
&*self.codegen_backend().metadata_loader(),
|
||||
self.compiler.register_lints.as_deref(),
|
||||
&pre_configured_attrs,
|
||||
));
|
||||
let cstore = RwLock::new(Box::new(CStore::new(stable_crate_id)) as _);
|
||||
let definitions = RwLock::new(Definitions::new(stable_crate_id));
|
||||
let source_span = AppendOnlyIndexVec::new();
|
||||
let _id = source_span.push(krate.spans.inner_span);
|
||||
debug_assert_eq!(_id, CRATE_DEF_ID);
|
||||
let untracked = Untracked { cstore, source_span, definitions };
|
||||
|
||||
// FIXME: Move these fields from session to tcx and make them immutable.
|
||||
sess.init_crate_types(crate_types);
|
||||
sess.stable_crate_id.set(stable_crate_id).expect("not yet initialized");
|
||||
sess.init_features(rustc_expand::config::features(sess, &pre_configured_attrs));
|
||||
|
||||
let qcx = passes::create_global_ctxt(
|
||||
self.compiler,
|
||||
lint_store,
|
||||
self.dep_graph()?.steal(),
|
||||
self.dep_graph(dep_graph_future),
|
||||
untracked,
|
||||
&self.gcx_cell,
|
||||
&self.arena,
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include "llvm/Support/DynamicLibrary.h"
|
||||
#include "llvm/Support/FormattedStream.h"
|
||||
#include "llvm/Support/JSON.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
#include "llvm/Support/Memory.h"
|
||||
#include "llvm/Support/SourceMgr.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
|
@ -25,11 +25,11 @@
|
||||
#if LLVM_VERSION_GE(17, 0)
|
||||
#include "llvm/Support/VirtualFileSystem.h"
|
||||
#endif
|
||||
#include "llvm/Support/Host.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Transforms/IPO/AlwaysInliner.h"
|
||||
#include "llvm/Transforms/IPO/FunctionImport.h"
|
||||
#include "llvm/Transforms/IPO/Internalize.h"
|
||||
#include "llvm/Transforms/IPO/LowerTypeTests.h"
|
||||
#include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h"
|
||||
#include "llvm/Transforms/Utils/AddDiscriminators.h"
|
||||
#include "llvm/Transforms/Utils/FunctionImportUtils.h"
|
||||
@ -609,6 +609,8 @@ enum class LLVMRustOptStage {
|
||||
struct LLVMRustSanitizerOptions {
|
||||
bool SanitizeAddress;
|
||||
bool SanitizeAddressRecover;
|
||||
bool SanitizeCFI;
|
||||
bool SanitizeKCFI;
|
||||
bool SanitizeMemory;
|
||||
bool SanitizeMemoryRecover;
|
||||
int SanitizeMemoryTrackOrigins;
|
||||
@ -625,6 +627,7 @@ LLVMRustOptimize(
|
||||
LLVMTargetMachineRef TMRef,
|
||||
LLVMRustPassBuilderOptLevel OptLevelRust,
|
||||
LLVMRustOptStage OptStage,
|
||||
bool IsLinkerPluginLTO,
|
||||
bool NoPrepopulatePasses, bool VerifyIR, bool UseThinLTOBuffers,
|
||||
bool MergeFunctions, bool UnrollLoops, bool SLPVectorize, bool LoopVectorize,
|
||||
bool DisableSimplifyLibCalls, bool EmitLifetimeMarkers,
|
||||
@ -736,6 +739,18 @@ LLVMRustOptimize(
|
||||
std::vector<std::function<void(ModulePassManager &, OptimizationLevel)>>
|
||||
OptimizerLastEPCallbacks;
|
||||
|
||||
if (!IsLinkerPluginLTO
|
||||
&& SanitizerOptions && SanitizerOptions->SanitizeCFI
|
||||
&& !NoPrepopulatePasses) {
|
||||
PipelineStartEPCallbacks.push_back(
|
||||
[](ModulePassManager &MPM, OptimizationLevel Level) {
|
||||
MPM.addPass(LowerTypeTestsPass(/*ExportSummary=*/nullptr,
|
||||
/*ImportSummary=*/nullptr,
|
||||
/*DropTypeTests=*/false));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (VerifyIR) {
|
||||
PipelineStartEPCallbacks.push_back(
|
||||
[VerifyIR](ModulePassManager &MPM, OptimizationLevel Level) {
|
||||
|
@ -1869,7 +1869,8 @@ extern "C" void LLVMRustContextConfigureDiagnosticHandler(
|
||||
LLVMContextRef C, LLVMDiagnosticHandlerTy DiagnosticHandlerCallback,
|
||||
void *DiagnosticHandlerContext, bool RemarkAllPasses,
|
||||
const char * const * RemarkPasses, size_t RemarkPassesLen,
|
||||
const char * RemarkFilePath
|
||||
const char * RemarkFilePath,
|
||||
bool PGOAvailable
|
||||
) {
|
||||
|
||||
class RustDiagnosticHandler final : public DiagnosticHandler {
|
||||
@ -1967,6 +1968,11 @@ extern "C" void LLVMRustContextConfigureDiagnosticHandler(
|
||||
std::unique_ptr<LLVMRemarkStreamer> LlvmRemarkStreamer;
|
||||
|
||||
if (RemarkFilePath != nullptr) {
|
||||
if (PGOAvailable) {
|
||||
// Enable PGO hotness data for remarks, if available
|
||||
unwrap(C)->setDiagnosticsHotnessRequested(true);
|
||||
}
|
||||
|
||||
std::error_code EC;
|
||||
RemarkFile = std::make_unique<ToolOutputFile>(
|
||||
RemarkFilePath,
|
||||
@ -2027,3 +2033,14 @@ extern "C" int32_t LLVMRustGetElementTypeArgIndex(LLVMValueRef CallSite) {
|
||||
extern "C" bool LLVMRustIsBitcode(char *ptr, size_t len) {
|
||||
return identify_magic(StringRef(ptr, len)) == file_magic::bitcode;
|
||||
}
|
||||
|
||||
extern "C" bool LLVMRustIsNonGVFunctionPointerTy(LLVMValueRef V) {
|
||||
if (unwrap<Value>(V)->getType()->isPointerTy()) {
|
||||
if (auto *GV = dyn_cast<GlobalValue>(unwrap<Value>(V))) {
|
||||
if (GV->getValueType()->isFunctionTy())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -20,7 +20,6 @@ use rustc_session::cstore::{CrateDepKind, CrateSource, ExternCrate};
|
||||
use rustc_session::lint;
|
||||
use rustc_session::output::validate_crate_name;
|
||||
use rustc_session::search_paths::PathKind;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
@ -262,9 +261,9 @@ impl CStore {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(sess: &Session) -> CStore {
|
||||
pub fn new(local_stable_crate_id: StableCrateId) -> CStore {
|
||||
let mut stable_crate_ids = StableCrateIdMap::default();
|
||||
stable_crate_ids.insert(sess.local_stable_crate_id(), LOCAL_CRATE);
|
||||
stable_crate_ids.insert(local_stable_crate_id, LOCAL_CRATE);
|
||||
CStore {
|
||||
// We add an empty entry for LOCAL_CRATE (which maps to zero) in
|
||||
// order to make array indices in `metas` match with the
|
||||
@ -544,6 +543,9 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
|
||||
self.sess,
|
||||
&**metadata_loader,
|
||||
name,
|
||||
// The all loop is because `--crate-type=rlib --crate-type=rlib` is
|
||||
// legal and produces both inside this type.
|
||||
self.sess.crate_types().iter().all(|c| *c == CrateType::Rlib),
|
||||
hash,
|
||||
extra_filename,
|
||||
false, // is_host
|
||||
|
@ -222,7 +222,7 @@ use rustc_data_structures::owned_slice::slice_owned;
|
||||
use rustc_data_structures::svh::Svh;
|
||||
use rustc_errors::{DiagnosticArgValue, FatalError, IntoDiagnosticArg};
|
||||
use rustc_fs_util::try_canonicalize;
|
||||
use rustc_session::config::{self, CrateType};
|
||||
use rustc_session::config;
|
||||
use rustc_session::cstore::{CrateSource, MetadataLoader};
|
||||
use rustc_session::filesearch::FileSearch;
|
||||
use rustc_session::search_paths::PathKind;
|
||||
@ -305,14 +305,12 @@ impl<'a> CrateLocator<'a> {
|
||||
sess: &'a Session,
|
||||
metadata_loader: &'a dyn MetadataLoader,
|
||||
crate_name: Symbol,
|
||||
is_rlib: bool,
|
||||
hash: Option<Svh>,
|
||||
extra_filename: Option<&'a str>,
|
||||
is_host: bool,
|
||||
path_kind: PathKind,
|
||||
) -> CrateLocator<'a> {
|
||||
// The all loop is because `--crate-type=rlib --crate-type=rlib` is
|
||||
// legal and produces both inside this type.
|
||||
let is_rlib = sess.crate_types().iter().all(|c| *c == CrateType::Rlib);
|
||||
let needs_object_code = sess.opts.output_types.should_codegen();
|
||||
// If we're producing an rlib, then we don't need object code.
|
||||
// Or, if we're not producing object code, then we don't need it either
|
||||
@ -883,9 +881,10 @@ fn find_plugin_registrar_impl<'a>(
|
||||
sess,
|
||||
metadata_loader,
|
||||
name,
|
||||
None, // hash
|
||||
None, // extra_filename
|
||||
true, // is_host
|
||||
false, // is_rlib
|
||||
None, // hash
|
||||
None, // extra_filename
|
||||
true, // is_host
|
||||
PathKind::Crate,
|
||||
);
|
||||
|
||||
|
@ -329,6 +329,9 @@ impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> {
|
||||
|
||||
/// Try to create an Allocation of `size` bytes, panics if there is not enough memory
|
||||
/// available to the compiler to do so.
|
||||
///
|
||||
/// Example use case: To obtain an Allocation filled with specific data,
|
||||
/// first call this function and then call write_scalar to fill in the right data.
|
||||
pub fn uninit(size: Size, align: Align) -> Self {
|
||||
match Self::uninit_inner(size, align, || {
|
||||
panic!("Allocation::uninit called with panic_on_fail had allocation failure");
|
||||
|
@ -184,8 +184,6 @@ pub enum InvalidProgramInfo<'tcx> {
|
||||
/// (which unfortunately typeck does not reject).
|
||||
/// Not using `FnAbiError` as that contains a nested `LayoutError`.
|
||||
FnAbiAdjustForForeignAbi(call::AdjustForForeignAbiError),
|
||||
/// SizeOf of unsized type was requested.
|
||||
SizeOfUnsizedType(Ty<'tcx>),
|
||||
/// We are runnning into a nonsense situation due to ConstProp violating our invariants.
|
||||
ConstPropNonsense,
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ use std::fmt::Write;
|
||||
|
||||
use crate::query::Providers;
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::{self as hir, LangItem};
|
||||
use rustc_span::def_id::LocalDefIdMap;
|
||||
@ -89,10 +90,18 @@ pub enum ClosureKind {
|
||||
FnOnce,
|
||||
}
|
||||
|
||||
impl<'tcx> ClosureKind {
|
||||
impl ClosureKind {
|
||||
/// This is the initial value used when doing upvar inference.
|
||||
pub const LATTICE_BOTTOM: ClosureKind = ClosureKind::Fn;
|
||||
|
||||
pub const fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
ClosureKind::Fn => "Fn",
|
||||
ClosureKind::FnMut => "FnMut",
|
||||
ClosureKind::FnOnce => "FnOnce",
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if a type that impls this closure kind
|
||||
/// must also implement `other`.
|
||||
pub fn extends(self, other: ty::ClosureKind) -> bool {
|
||||
@ -115,7 +124,7 @@ impl<'tcx> ClosureKind {
|
||||
|
||||
/// Returns the representative scalar type for this closure kind.
|
||||
/// See `Ty::to_opt_closure_kind` for more details.
|
||||
pub fn to_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
|
||||
pub fn to_ty<'tcx>(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
|
||||
match self {
|
||||
ClosureKind::Fn => tcx.types.i8,
|
||||
ClosureKind::FnMut => tcx.types.i16,
|
||||
@ -124,6 +133,12 @@ impl<'tcx> ClosureKind {
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoDiagnosticArg for ClosureKind {
|
||||
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
|
||||
DiagnosticArgValue::Str(self.as_str().into())
|
||||
}
|
||||
}
|
||||
|
||||
/// A composite describing a `Place` that is captured by a closure.
|
||||
#[derive(PartialEq, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
|
||||
#[derive(TypeFoldable, TypeVisitable)]
|
||||
|
@ -1931,6 +1931,84 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
)
|
||||
}
|
||||
|
||||
/// Given the def-id of an early-bound lifetime on an RPIT corresponding to
|
||||
/// a duplicated captured lifetime, map it back to the early- or late-bound
|
||||
/// lifetime of the function from which it originally as captured. If it is
|
||||
/// a late-bound lifetime, this will represent the liberated (`ReFree`) lifetime
|
||||
/// of the signature.
|
||||
// FIXME(RPITIT): if we ever synthesize new lifetimes for RPITITs and not just
|
||||
// re-use the generics of the opaque, this function will need to be tweaked slightly.
|
||||
pub fn map_rpit_lifetime_to_fn_lifetime(
|
||||
self,
|
||||
mut rpit_lifetime_param_def_id: LocalDefId,
|
||||
) -> ty::Region<'tcx> {
|
||||
debug_assert!(
|
||||
matches!(self.def_kind(rpit_lifetime_param_def_id), DefKind::LifetimeParam),
|
||||
"{rpit_lifetime_param_def_id:?} is a {}",
|
||||
self.def_descr(rpit_lifetime_param_def_id.to_def_id())
|
||||
);
|
||||
|
||||
loop {
|
||||
let parent = self.local_parent(rpit_lifetime_param_def_id);
|
||||
let hir::OpaqueTy { lifetime_mapping, .. } =
|
||||
self.hir().get_by_def_id(parent).expect_item().expect_opaque_ty();
|
||||
|
||||
let Some((lifetime, _)) = lifetime_mapping
|
||||
.iter()
|
||||
.find(|(_, duplicated_param)| *duplicated_param == rpit_lifetime_param_def_id)
|
||||
else {
|
||||
bug!("duplicated lifetime param should be present");
|
||||
};
|
||||
|
||||
match self.named_bound_var(lifetime.hir_id) {
|
||||
Some(resolve_bound_vars::ResolvedArg::EarlyBound(ebv)) => {
|
||||
let new_parent = self.parent(ebv);
|
||||
|
||||
// If we map to another opaque, then it should be a parent
|
||||
// of the opaque we mapped from. Continue mapping.
|
||||
if matches!(self.def_kind(new_parent), DefKind::OpaqueTy) {
|
||||
debug_assert_eq!(self.parent(parent.to_def_id()), new_parent);
|
||||
rpit_lifetime_param_def_id = ebv.expect_local();
|
||||
continue;
|
||||
}
|
||||
|
||||
let generics = self.generics_of(new_parent);
|
||||
return ty::Region::new_early_bound(
|
||||
self,
|
||||
ty::EarlyBoundRegion {
|
||||
def_id: ebv,
|
||||
index: generics
|
||||
.param_def_id_to_index(self, ebv)
|
||||
.expect("early-bound var should be present in fn generics"),
|
||||
name: self.hir().name(self.local_def_id_to_hir_id(ebv.expect_local())),
|
||||
},
|
||||
);
|
||||
}
|
||||
Some(resolve_bound_vars::ResolvedArg::LateBound(_, _, lbv)) => {
|
||||
let new_parent = self.parent(lbv);
|
||||
return ty::Region::new_free(
|
||||
self,
|
||||
new_parent,
|
||||
ty::BoundRegionKind::BrNamed(
|
||||
lbv,
|
||||
self.hir().name(self.local_def_id_to_hir_id(lbv.expect_local())),
|
||||
),
|
||||
);
|
||||
}
|
||||
Some(resolve_bound_vars::ResolvedArg::Error(guar)) => {
|
||||
return ty::Region::new_error(self, guar);
|
||||
}
|
||||
_ => {
|
||||
return ty::Region::new_error_with_message(
|
||||
self,
|
||||
lifetime.ident.span,
|
||||
"cannot resolve lifetime",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether the `def_id` counts as const fn in the current crate, considering all active
|
||||
/// feature gates
|
||||
pub fn is_const_fn(self, def_id: DefId) -> bool {
|
||||
@ -1963,9 +2041,9 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
matches!(
|
||||
node,
|
||||
hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Impl(hir::Impl { constness: hir::Constness::Const, .. }),
|
||||
kind: hir::ItemKind::Impl(hir::Impl { generics, .. }),
|
||||
..
|
||||
})
|
||||
}) if generics.params.iter().any(|p| self.has_attr(p.def_id, sym::rustc_host))
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1239,6 +1239,8 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: SpecAbi) ->
|
||||
| EfiApi
|
||||
| AvrInterrupt
|
||||
| AvrNonBlockingInterrupt
|
||||
| RiscvInterruptM
|
||||
| RiscvInterruptS
|
||||
| CCmseNonSecureCall
|
||||
| Wasm
|
||||
| PlatformIntrinsic
|
||||
|
@ -2841,6 +2841,11 @@ define_print_and_forward_display! {
|
||||
|
||||
ty::TraitPredicate<'tcx> {
|
||||
p!(print(self.trait_ref.self_ty()), ": ");
|
||||
if let Some(idx) = cx.tcx().generics_of(self.trait_ref.def_id).host_effect_index {
|
||||
if self.trait_ref.args.const_at(idx) != cx.tcx().consts.true_ {
|
||||
p!("~const ");
|
||||
}
|
||||
}
|
||||
// FIXME(effects) print `~const` here
|
||||
if let ty::ImplPolarity::Negative = self.polarity {
|
||||
p!("!");
|
||||
@ -2870,11 +2875,7 @@ define_print_and_forward_display! {
|
||||
}
|
||||
|
||||
ty::ClosureKind {
|
||||
match *self {
|
||||
ty::ClosureKind::Fn => p!("Fn"),
|
||||
ty::ClosureKind::FnMut => p!("FnMut"),
|
||||
ty::ClosureKind::FnOnce => p!("FnOnce"),
|
||||
}
|
||||
p!(write("{}", self.as_str()))
|
||||
}
|
||||
|
||||
ty::Predicate<'tcx> {
|
||||
|
@ -30,6 +30,8 @@ fn abi_can_unwind(abi: Abi) -> bool {
|
||||
| EfiApi
|
||||
| AvrInterrupt
|
||||
| AvrNonBlockingInterrupt
|
||||
| RiscvInterruptM
|
||||
| RiscvInterruptS
|
||||
| CCmseNonSecureCall
|
||||
| Wasm
|
||||
| RustIntrinsic
|
||||
|
@ -75,7 +75,7 @@ mod errors;
|
||||
mod ffi_unwind_calls;
|
||||
mod function_item_references;
|
||||
mod generator;
|
||||
mod inline;
|
||||
pub mod inline;
|
||||
mod instsimplify;
|
||||
mod large_enums;
|
||||
mod lower_intrinsics;
|
||||
@ -431,7 +431,9 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &
|
||||
tcx.alloc_steal_mir(body)
|
||||
}
|
||||
|
||||
fn run_analysis_to_runtime_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
// Made public such that `mir_drops_elaborated_and_const_checked` can be overridden
|
||||
// by custom rustc drivers, running all the steps by themselves.
|
||||
pub fn run_analysis_to_runtime_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
assert!(body.phase == MirPhase::Analysis(AnalysisPhase::Initial));
|
||||
let did = body.source.def_id();
|
||||
|
||||
|
@ -732,13 +732,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
|
||||
// For implementations of traits, check the stability of each item
|
||||
// individually as it's possible to have a stable trait with unstable
|
||||
// items.
|
||||
hir::ItemKind::Impl(hir::Impl {
|
||||
of_trait: Some(ref t),
|
||||
self_ty,
|
||||
items,
|
||||
constness,
|
||||
..
|
||||
}) => {
|
||||
hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref t), self_ty, items, .. }) => {
|
||||
let features = self.tcx.features();
|
||||
if features.staged_api {
|
||||
let attrs = self.tcx.hir().attrs(item.hir_id());
|
||||
@ -769,7 +763,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
|
||||
// `#![feature(const_trait_impl)]` is unstable, so any impl declared stable
|
||||
// needs to have an error emitted.
|
||||
if features.const_trait_impl
|
||||
&& *constness == hir::Constness::Const
|
||||
&& self.tcx.is_const_trait_impl_raw(item.owner_id.to_def_id())
|
||||
&& const_stab.is_some_and(|(stab, _)| stab.is_const_stable())
|
||||
{
|
||||
self.tcx.sess.emit_err(errors::TraitImplConstStable { span: item.span });
|
||||
|
@ -89,7 +89,9 @@ session_sanitizer_cfi_generalize_pointers_requires_cfi = `-Zsanitizer-cfi-genera
|
||||
|
||||
session_sanitizer_cfi_normalize_integers_requires_cfi = `-Zsanitizer-cfi-normalize-integers` requires `-Zsanitizer=cfi` or `-Zsanitizer=kcfi`
|
||||
|
||||
session_sanitizer_cfi_requires_lto = `-Zsanitizer=cfi` requires `-Clto`, `-Clto=thin`, or `-Clinker-plugin-lto`
|
||||
session_sanitizer_cfi_requires_lto = `-Zsanitizer=cfi` requires `-Clto` or `-Clinker-plugin-lto`
|
||||
|
||||
session_sanitizer_cfi_requires_single_codegen_unit = `-Zsanitizer=cfi` with `-Clto` requires `-Ccodegen-units=1`
|
||||
|
||||
session_sanitizer_not_supported = {$us} sanitizer is not supported for this target
|
||||
|
||||
|
@ -114,6 +114,10 @@ pub struct CannotEnableCrtStaticLinux;
|
||||
#[diag(session_sanitizer_cfi_requires_lto)]
|
||||
pub struct SanitizerCfiRequiresLto;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(session_sanitizer_cfi_requires_single_codegen_unit)]
|
||||
pub struct SanitizerCfiRequiresSingleCodegenUnit;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(session_sanitizer_cfi_canonical_jump_tables_requires_cfi)]
|
||||
pub struct SanitizerCfiCanonicalJumpTablesRequiresCfi;
|
||||
|
@ -1619,13 +1619,19 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
|
||||
|
||||
// LLVM CFI requires LTO.
|
||||
if sess.is_sanitizer_cfi_enabled()
|
||||
&& !(sess.lto() == config::Lto::Fat
|
||||
|| sess.lto() == config::Lto::Thin
|
||||
|| sess.opts.cg.linker_plugin_lto.enabled())
|
||||
&& !(sess.lto() == config::Lto::Fat || sess.opts.cg.linker_plugin_lto.enabled())
|
||||
{
|
||||
sess.emit_err(errors::SanitizerCfiRequiresLto);
|
||||
}
|
||||
|
||||
// LLVM CFI using rustc LTO requires a single codegen unit.
|
||||
if sess.is_sanitizer_cfi_enabled()
|
||||
&& sess.lto() == config::Lto::Fat
|
||||
&& !(sess.codegen_units().as_usize() == 1)
|
||||
{
|
||||
sess.emit_err(errors::SanitizerCfiRequiresSingleCodegenUnit);
|
||||
}
|
||||
|
||||
// LLVM CFI is incompatible with LLVM KCFI.
|
||||
if sess.is_sanitizer_cfi_enabled() && sess.is_sanitizer_kcfi_enabled() {
|
||||
sess.emit_err(errors::CannotMixAndMatchSanitizers {
|
||||
|
@ -112,6 +112,10 @@ impl<'tcx> Tables<'tcx> {
|
||||
stable_mir::ty::TraitDef(self.create_def_id(did))
|
||||
}
|
||||
|
||||
pub fn const_def(&mut self, did: DefId) -> stable_mir::ty::ConstDef {
|
||||
stable_mir::ty::ConstDef(self.create_def_id(did))
|
||||
}
|
||||
|
||||
fn create_def_id(&mut self, did: DefId) -> stable_mir::DefId {
|
||||
// FIXME: this becomes inefficient when we have too many ids
|
||||
for (i, &d) in self.def_ids.iter().enumerate() {
|
||||
|
@ -9,11 +9,14 @@
|
||||
|
||||
use crate::rustc_internal::{self, opaque};
|
||||
use crate::stable_mir::mir::{CopyNonOverlapping, UserTypeProjection, VariantIdx};
|
||||
use crate::stable_mir::ty::{FloatTy, IntTy, Movability, RigidTy, TyKind, UintTy};
|
||||
use crate::stable_mir::ty::{
|
||||
allocation_filter, new_allocation, FloatTy, IntTy, Movability, RigidTy, TyKind, UintTy,
|
||||
};
|
||||
use crate::stable_mir::{self, Context};
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::mir::coverage::CodeRegion;
|
||||
use rustc_middle::mir::{self};
|
||||
use rustc_middle::mir::interpret::alloc_range;
|
||||
use rustc_middle::mir::{self, ConstantKind};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, Variance};
|
||||
use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE};
|
||||
use rustc_target::abi::FieldIdx;
|
||||
@ -877,6 +880,8 @@ impl<'tcx> Stable<'tcx> for ty::FnSig<'tcx> {
|
||||
abi::Abi::PlatformIntrinsic => Abi::PlatformIntrinsic,
|
||||
abi::Abi::Unadjusted => Abi::Unadjusted,
|
||||
abi::Abi::RustCold => Abi::RustCold,
|
||||
abi::Abi::RiscvInterruptM => Abi::RiscvInterruptM,
|
||||
abi::Abi::RiscvInterruptS => Abi::RiscvInterruptS,
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -1080,30 +1085,7 @@ impl<'tcx> Stable<'tcx> for mir::interpret::Allocation {
|
||||
type T = stable_mir::ty::Allocation;
|
||||
|
||||
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||
let size = self.size();
|
||||
let mut bytes: Vec<Option<u8>> = self
|
||||
.inspect_with_uninit_and_ptr_outside_interpreter(0..size.bytes_usize())
|
||||
.iter()
|
||||
.copied()
|
||||
.map(Some)
|
||||
.collect();
|
||||
for (i, b) in bytes.iter_mut().enumerate() {
|
||||
if !self.init_mask().get(rustc_target::abi::Size::from_bytes(i)) {
|
||||
*b = None;
|
||||
}
|
||||
}
|
||||
stable_mir::ty::Allocation {
|
||||
bytes: bytes,
|
||||
provenance: {
|
||||
let mut ptrs = Vec::new();
|
||||
for (size, prov) in self.provenance().ptrs().iter() {
|
||||
ptrs.push((size.bytes_usize(), opaque(prov)));
|
||||
}
|
||||
stable_mir::ty::ProvenanceMap { ptrs }
|
||||
},
|
||||
align: self.align.bytes(),
|
||||
mutability: self.mutability.stable(tables),
|
||||
}
|
||||
allocation_filter(self, alloc_range(rustc_target::abi::Size::ZERO, self.size()), tables)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1145,3 +1127,30 @@ impl<'tcx> Stable<'tcx> for ty::TraitDef {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx> for rustc_middle::mir::ConstantKind<'tcx> {
|
||||
type T = stable_mir::ty::ConstantKind;
|
||||
|
||||
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||
match self {
|
||||
ConstantKind::Ty(c) => match c.kind() {
|
||||
ty::Value(val) => {
|
||||
let const_val = tables.tcx.valtree_to_const_val((c.ty(), val));
|
||||
stable_mir::ty::ConstantKind::Allocated(new_allocation(self, const_val, tables))
|
||||
}
|
||||
_ => todo!(),
|
||||
},
|
||||
ConstantKind::Unevaluated(unev_const, ty) => {
|
||||
stable_mir::ty::ConstantKind::Unevaluated(stable_mir::ty::UnevaluatedConst {
|
||||
ty: tables.intern_ty(*ty),
|
||||
def: tables.const_def(unev_const.def),
|
||||
args: unev_const.args.stable(tables),
|
||||
promoted: unev_const.promoted.map(|u| u.as_u32()),
|
||||
})
|
||||
}
|
||||
ConstantKind::Val(val, _) => {
|
||||
stable_mir::ty::ConstantKind::Allocated(new_allocation(self, *val, tables))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,10 @@
|
||||
use rustc_middle::mir::interpret::{alloc_range, AllocRange, ConstValue, Pointer};
|
||||
|
||||
use super::{mir::Mutability, mir::Safety, with, DefId};
|
||||
use crate::rustc_internal::Opaque;
|
||||
use crate::{
|
||||
rustc_internal::{opaque, Opaque},
|
||||
rustc_smir::{Stable, Tables},
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Ty(pub usize);
|
||||
@ -105,6 +110,9 @@ pub struct AliasDef(pub(crate) DefId);
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct TraitDef(pub(crate) DefId);
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct ConstDef(pub(crate) DefId);
|
||||
|
||||
impl TraitDef {
|
||||
pub fn trait_decl(&self) -> TraitDecl {
|
||||
with(|cx| cx.trait_decl(self))
|
||||
@ -178,6 +186,8 @@ pub enum Abi {
|
||||
PlatformIntrinsic,
|
||||
Unadjusted,
|
||||
RustCold,
|
||||
RiscvInterruptM,
|
||||
RiscvInterruptS,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@ -248,6 +258,7 @@ pub type Bytes = Vec<Option<u8>>;
|
||||
pub type Size = usize;
|
||||
pub type Prov = Opaque;
|
||||
pub type Align = u64;
|
||||
pub type Promoted = u32;
|
||||
pub type InitMaskMaterialized = Vec<u64>;
|
||||
|
||||
/// Stores the provenance information of pointers stored in memory.
|
||||
@ -266,6 +277,142 @@ pub struct Allocation {
|
||||
pub mutability: Mutability,
|
||||
}
|
||||
|
||||
impl Allocation {
|
||||
/// Creates new empty `Allocation` from given `Align`.
|
||||
fn new_empty_allocation(align: rustc_target::abi::Align) -> Allocation {
|
||||
Allocation {
|
||||
bytes: Vec::new(),
|
||||
provenance: ProvenanceMap { ptrs: Vec::new() },
|
||||
align: align.bytes(),
|
||||
mutability: Mutability::Not,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We need this method instead of a Stable implementation
|
||||
// because we need to get `Ty` of the const we are trying to create, to do that
|
||||
// we need to have access to `ConstantKind` but we can't access that inside Stable impl.
|
||||
pub fn new_allocation<'tcx>(
|
||||
const_kind: &rustc_middle::mir::ConstantKind<'tcx>,
|
||||
const_value: ConstValue<'tcx>,
|
||||
tables: &mut Tables<'tcx>,
|
||||
) -> Allocation {
|
||||
match const_value {
|
||||
ConstValue::Scalar(scalar) => {
|
||||
let size = scalar.size();
|
||||
let align = tables
|
||||
.tcx
|
||||
.layout_of(rustc_middle::ty::ParamEnv::reveal_all().and(const_kind.ty()))
|
||||
.unwrap()
|
||||
.align;
|
||||
let mut allocation = rustc_middle::mir::interpret::Allocation::uninit(size, align.abi);
|
||||
allocation
|
||||
.write_scalar(&tables.tcx, alloc_range(rustc_target::abi::Size::ZERO, size), scalar)
|
||||
.unwrap();
|
||||
allocation.stable(tables)
|
||||
}
|
||||
ConstValue::ZeroSized => {
|
||||
let align = tables
|
||||
.tcx
|
||||
.layout_of(rustc_middle::ty::ParamEnv::empty().and(const_kind.ty()))
|
||||
.unwrap()
|
||||
.align;
|
||||
Allocation::new_empty_allocation(align.abi)
|
||||
}
|
||||
ConstValue::Slice { data, start, end } => {
|
||||
let alloc_id = tables.tcx.create_memory_alloc(data);
|
||||
let ptr = Pointer::new(alloc_id, rustc_target::abi::Size::from_bytes(start));
|
||||
let scalar_ptr = rustc_middle::mir::interpret::Scalar::from_pointer(ptr, &tables.tcx);
|
||||
let scalar_len = rustc_middle::mir::interpret::Scalar::from_target_usize(
|
||||
(end - start) as u64,
|
||||
&tables.tcx,
|
||||
);
|
||||
let layout = tables
|
||||
.tcx
|
||||
.layout_of(rustc_middle::ty::ParamEnv::reveal_all().and(const_kind.ty()))
|
||||
.unwrap();
|
||||
let mut allocation =
|
||||
rustc_middle::mir::interpret::Allocation::uninit(layout.size, layout.align.abi);
|
||||
allocation
|
||||
.write_scalar(
|
||||
&tables.tcx,
|
||||
alloc_range(rustc_target::abi::Size::ZERO, tables.tcx.data_layout.pointer_size),
|
||||
scalar_ptr,
|
||||
)
|
||||
.unwrap();
|
||||
allocation
|
||||
.write_scalar(
|
||||
&tables.tcx,
|
||||
alloc_range(tables.tcx.data_layout.pointer_size, scalar_len.size()),
|
||||
scalar_len,
|
||||
)
|
||||
.unwrap();
|
||||
allocation.stable(tables)
|
||||
}
|
||||
ConstValue::ByRef { alloc, offset } => {
|
||||
let ty_size = tables
|
||||
.tcx
|
||||
.layout_of(rustc_middle::ty::ParamEnv::reveal_all().and(const_kind.ty()))
|
||||
.unwrap()
|
||||
.size;
|
||||
allocation_filter(&alloc.0, alloc_range(offset, ty_size), tables)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates an `Allocation` only from information within the `AllocRange`.
|
||||
pub fn allocation_filter<'tcx>(
|
||||
alloc: &rustc_middle::mir::interpret::Allocation,
|
||||
alloc_range: AllocRange,
|
||||
tables: &mut Tables<'tcx>,
|
||||
) -> Allocation {
|
||||
let mut bytes: Vec<Option<u8>> = alloc
|
||||
.inspect_with_uninit_and_ptr_outside_interpreter(
|
||||
alloc_range.start.bytes_usize()..alloc_range.end().bytes_usize(),
|
||||
)
|
||||
.iter()
|
||||
.copied()
|
||||
.map(Some)
|
||||
.collect();
|
||||
for (i, b) in bytes.iter_mut().enumerate() {
|
||||
if !alloc
|
||||
.init_mask()
|
||||
.get(rustc_target::abi::Size::from_bytes(i + alloc_range.start.bytes_usize()))
|
||||
{
|
||||
*b = None;
|
||||
}
|
||||
}
|
||||
let mut ptrs = Vec::new();
|
||||
for (offset, prov) in alloc
|
||||
.provenance()
|
||||
.ptrs()
|
||||
.iter()
|
||||
.filter(|a| a.0 >= alloc_range.start && a.0 <= alloc_range.end())
|
||||
{
|
||||
ptrs.push((offset.bytes_usize() - alloc_range.start.bytes_usize(), opaque(prov)));
|
||||
}
|
||||
Allocation {
|
||||
bytes: bytes,
|
||||
provenance: ProvenanceMap { ptrs },
|
||||
align: alloc.align.bytes(),
|
||||
mutability: alloc.mutability.stable(tables),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ConstantKind {
|
||||
Allocated(Allocation),
|
||||
Unevaluated(UnevaluatedConst),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct UnevaluatedConst {
|
||||
pub ty: Ty,
|
||||
pub def: ConstDef,
|
||||
pub args: GenericArgs,
|
||||
pub promoted: Option<Promoted>,
|
||||
}
|
||||
|
||||
pub enum TraitSpecializationKind {
|
||||
None,
|
||||
Marker,
|
||||
|
@ -326,6 +326,7 @@ symbols! {
|
||||
abi_efiapi,
|
||||
abi_msp430_interrupt,
|
||||
abi_ptx,
|
||||
abi_riscv_interrupt,
|
||||
abi_sysv64,
|
||||
abi_thiscall,
|
||||
abi_unadjusted,
|
||||
|
@ -603,6 +603,25 @@ pub enum Conv {
|
||||
AmdGpuKernel,
|
||||
AvrInterrupt,
|
||||
AvrNonBlockingInterrupt,
|
||||
|
||||
RiscvInterrupt {
|
||||
kind: RiscvInterruptKind,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
|
||||
pub enum RiscvInterruptKind {
|
||||
Machine,
|
||||
Supervisor,
|
||||
}
|
||||
|
||||
impl RiscvInterruptKind {
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Machine => "machine",
|
||||
Self::Supervisor => "supervisor",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Metadata describing how the arguments to a native function
|
||||
@ -753,6 +772,12 @@ impl FromStr for Conv {
|
||||
"AmdGpuKernel" => Ok(Conv::AmdGpuKernel),
|
||||
"AvrInterrupt" => Ok(Conv::AvrInterrupt),
|
||||
"AvrNonBlockingInterrupt" => Ok(Conv::AvrNonBlockingInterrupt),
|
||||
"RiscvInterrupt(machine)" => {
|
||||
Ok(Conv::RiscvInterrupt { kind: RiscvInterruptKind::Machine })
|
||||
}
|
||||
"RiscvInterrupt(supervisor)" => {
|
||||
Ok(Conv::RiscvInterrupt { kind: RiscvInterruptKind::Supervisor })
|
||||
}
|
||||
_ => Err(format!("'{s}' is not a valid value for entry function call convention.")),
|
||||
}
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ impl<'a, Ty> Deref for TyAndLayout<'a, Ty> {
|
||||
|
||||
/// Trait that needs to be implemented by the higher-level type representation
|
||||
/// (e.g. `rustc_middle::ty::Ty`), to provide `rustc_target::abi` functionality.
|
||||
pub trait TyAbiInterface<'a, C>: Sized {
|
||||
pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug {
|
||||
fn ty_and_layout_for_variant(
|
||||
this: TyAndLayout<'a, Self>,
|
||||
cx: &C,
|
||||
@ -135,6 +135,11 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
|
||||
for index in indices {
|
||||
offset += layout.fields.offset(index);
|
||||
layout = layout.field(cx, index);
|
||||
assert!(
|
||||
layout.is_sized(),
|
||||
"offset of unsized field (type {:?}) cannot be computed statically",
|
||||
layout.ty
|
||||
);
|
||||
}
|
||||
|
||||
offset
|
||||
|
@ -92,6 +92,7 @@ impl<A: ToJson> ToJson for Option<A> {
|
||||
|
||||
impl ToJson for crate::abi::call::Conv {
|
||||
fn to_json(&self) -> Json {
|
||||
let buf: String;
|
||||
let s = match self {
|
||||
Self::C => "C",
|
||||
Self::Rust => "Rust",
|
||||
@ -110,6 +111,10 @@ impl ToJson for crate::abi::call::Conv {
|
||||
Self::AmdGpuKernel => "AmdGpuKernel",
|
||||
Self::AvrInterrupt => "AvrInterrupt",
|
||||
Self::AvrNonBlockingInterrupt => "AvrNonBlockingInterrupt",
|
||||
Self::RiscvInterrupt { kind } => {
|
||||
buf = format!("RiscvInterrupt({})", kind.as_str());
|
||||
&buf
|
||||
}
|
||||
};
|
||||
Json::String(s.to_owned())
|
||||
}
|
||||
|
16
compiler/rustc_target/src/spec/aarch64_unknown_teeos.rs
Normal file
16
compiler/rustc_target/src/spec/aarch64_unknown_teeos.rs
Normal file
@ -0,0 +1,16 @@
|
||||
use crate::spec::Target;
|
||||
|
||||
pub fn target() -> Target {
|
||||
let mut base = super::teeos_base::opts();
|
||||
base.features = "+strict-align,+neon,+fp-armv8".into();
|
||||
base.max_atomic_width = Some(128);
|
||||
base.linker = Some("aarch64-linux-gnu-ld".into());
|
||||
|
||||
Target {
|
||||
llvm_target: "aarch64-unknown-none".into(),
|
||||
pointer_width: 64,
|
||||
data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(),
|
||||
arch: "aarch64".into(),
|
||||
options: base,
|
||||
}
|
||||
}
|
@ -38,6 +38,8 @@ pub enum Abi {
|
||||
PlatformIntrinsic,
|
||||
Unadjusted,
|
||||
RustCold,
|
||||
RiscvInterruptM,
|
||||
RiscvInterruptS,
|
||||
}
|
||||
|
||||
impl Abi {
|
||||
@ -107,11 +109,29 @@ const AbiDatas: &[AbiData] = &[
|
||||
AbiData { abi: Abi::PlatformIntrinsic, name: "platform-intrinsic" },
|
||||
AbiData { abi: Abi::Unadjusted, name: "unadjusted" },
|
||||
AbiData { abi: Abi::RustCold, name: "rust-cold" },
|
||||
AbiData { abi: Abi::RiscvInterruptM, name: "riscv-interrupt-m" },
|
||||
AbiData { abi: Abi::RiscvInterruptS, name: "riscv-interrupt-s" },
|
||||
];
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum AbiUnsupported {
|
||||
Unrecognized,
|
||||
Reason { explain: &'static str },
|
||||
}
|
||||
|
||||
/// Returns the ABI with the given name (if any).
|
||||
pub fn lookup(name: &str) -> Option<Abi> {
|
||||
AbiDatas.iter().find(|abi_data| name == abi_data.name).map(|&x| x.abi)
|
||||
pub fn lookup(name: &str) -> Result<Abi, AbiUnsupported> {
|
||||
AbiDatas.iter().find(|abi_data| name == abi_data.name).map(|&x| x.abi).ok_or_else(|| match name {
|
||||
"riscv-interrupt" => AbiUnsupported::Reason {
|
||||
explain: "please use one of riscv-interrupt-m or riscv-interrupt-s for machine- or supervisor-level interrupts, respectively",
|
||||
},
|
||||
"riscv-interrupt-u" => AbiUnsupported::Reason {
|
||||
explain: "user-mode interrupt handlers have been removed from LLVM pending standardization, see: https://reviews.llvm.org/D149314",
|
||||
},
|
||||
|
||||
_ => AbiUnsupported::Unrecognized,
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
pub fn all_names() -> Vec<&'static str> {
|
||||
@ -200,6 +220,10 @@ pub fn is_stable(name: &str) -> Result<(), AbiDisabled> {
|
||||
feature: sym::abi_avr_interrupt,
|
||||
explain: "avr-interrupt and avr-non-blocking-interrupt ABIs are experimental and subject to change",
|
||||
}),
|
||||
"riscv-interrupt-m" | "riscv-interrupt-s" => Err(AbiDisabled::Unstable {
|
||||
feature: sym::abi_riscv_interrupt,
|
||||
explain: "riscv-interrupt ABIs are experimental and subject to change",
|
||||
}),
|
||||
"C-cmse-nonsecure-call" => Err(AbiDisabled::Unstable {
|
||||
feature: sym::abi_c_cmse_nonsecure_call,
|
||||
explain: "C-cmse-nonsecure-call ABI is experimental and subject to change",
|
||||
@ -260,6 +284,8 @@ impl Abi {
|
||||
PlatformIntrinsic => 32,
|
||||
Unadjusted => 33,
|
||||
RustCold => 34,
|
||||
RiscvInterruptM => 35,
|
||||
RiscvInterruptS => 36,
|
||||
};
|
||||
debug_assert!(
|
||||
AbiDatas
|
||||
|
@ -4,19 +4,19 @@ use super::*;
|
||||
#[test]
|
||||
fn lookup_Rust() {
|
||||
let abi = lookup("Rust");
|
||||
assert!(abi.is_some() && abi.unwrap().data().name == "Rust");
|
||||
assert!(abi.is_ok() && abi.unwrap().data().name == "Rust");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lookup_cdecl() {
|
||||
let abi = lookup("cdecl");
|
||||
assert!(abi.is_some() && abi.unwrap().data().name == "cdecl");
|
||||
assert!(abi.is_ok() && abi.unwrap().data().name == "cdecl");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lookup_baz() {
|
||||
let abi = lookup("baz");
|
||||
assert!(abi.is_none());
|
||||
assert!(matches!(abi, Err(AbiUnsupported::Unrecognized)))
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -83,6 +83,7 @@ mod openbsd_base;
|
||||
mod redox_base;
|
||||
mod solaris_base;
|
||||
mod solid_base;
|
||||
mod teeos_base;
|
||||
mod thumb_base;
|
||||
mod uefi_msvc_base;
|
||||
mod unikraft_linux_musl_base;
|
||||
@ -1494,6 +1495,8 @@ supported_targets! {
|
||||
|
||||
("x86_64-unknown-none", x86_64_unknown_none),
|
||||
|
||||
("aarch64-unknown-teeos", aarch64_unknown_teeos),
|
||||
|
||||
("mips64-openwrt-linux-musl", mips64_openwrt_linux_musl),
|
||||
|
||||
("aarch64-unknown-nto-qnx710", aarch64_unknown_nto_qnx_710),
|
||||
@ -2267,6 +2270,7 @@ impl Target {
|
||||
PtxKernel => self.arch == "nvptx64",
|
||||
Msp430Interrupt => self.arch == "msp430",
|
||||
AmdGpuKernel => self.arch == "amdgcn",
|
||||
RiscvInterruptM | RiscvInterruptS => ["riscv32", "riscv64"].contains(&&self.arch[..]),
|
||||
AvrInterrupt | AvrNonBlockingInterrupt => self.arch == "avr",
|
||||
Wasm => ["wasm32", "wasm64"].contains(&&self.arch[..]),
|
||||
Thiscall { .. } => self.arch == "x86",
|
||||
@ -2698,7 +2702,7 @@ impl Target {
|
||||
let name = (stringify!($key_name)).replace("_", "-");
|
||||
obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
|
||||
match lookup_abi(s) {
|
||||
Some(abi) => base.$key_name = Some(abi),
|
||||
Ok(abi) => base.$key_name = Some(abi),
|
||||
_ => return Some(Err(format!("'{}' is not a valid value for abi", s))),
|
||||
}
|
||||
Some(Ok(()))
|
||||
|
29
compiler/rustc_target/src/spec/teeos_base.rs
Normal file
29
compiler/rustc_target/src/spec/teeos_base.rs
Normal file
@ -0,0 +1,29 @@
|
||||
use super::{Cc, LinkerFlavor, Lld, PanicStrategy};
|
||||
use crate::spec::{RelroLevel, TargetOptions};
|
||||
|
||||
pub fn opts() -> TargetOptions {
|
||||
let lld_args = &["-zmax-page-size=4096", "-znow", "-ztext", "--execute-only"];
|
||||
let cc_args = &["-Wl,-zmax-page-size=4096", "-Wl,-znow", "-Wl,-ztext", "-mexecute-only"];
|
||||
|
||||
let mut pre_link_args = TargetOptions::link_args(LinkerFlavor::Gnu(Cc::No, Lld::No), lld_args);
|
||||
super::add_link_args(&mut pre_link_args, LinkerFlavor::Gnu(Cc::Yes, Lld::No), cc_args);
|
||||
|
||||
TargetOptions {
|
||||
os: "teeos".into(),
|
||||
vendor: "unknown".into(),
|
||||
dynamic_linking: true,
|
||||
linker_flavor: LinkerFlavor::Gnu(Cc::Yes, Lld::No),
|
||||
// rpath hardcodes -Wl, so it can't be used together with ld.lld.
|
||||
// C TAs also don't support rpath, so this is fine.
|
||||
has_rpath: false,
|
||||
// Note: Setting has_thread_local to true causes an error when
|
||||
// loading / dyn-linking the TA
|
||||
has_thread_local: false,
|
||||
position_independent_executables: true,
|
||||
relro_level: RelroLevel::Full,
|
||||
crt_static_respected: true,
|
||||
pre_link_args,
|
||||
panic_strategy: PanicStrategy::Abort,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
@ -8,6 +8,15 @@ trait_selection_adjust_signature_remove_borrow = consider adjusting the signatur
|
||||
*[other] arguments
|
||||
}
|
||||
|
||||
trait_selection_closure_fn_mut_label = closure is `FnMut` because it mutates the variable `{$place}` here
|
||||
|
||||
trait_selection_closure_fn_once_label = closure is `FnOnce` because it moves the variable `{$place}` out of its environment
|
||||
|
||||
trait_selection_closure_kind_mismatch = expected a closure that implements the `{$expected}` trait, but this closure only implements `{$found}`
|
||||
.label = this closure implements `{$found}`, not `{$expected}`
|
||||
|
||||
trait_selection_closure_kind_requirement = the requirement to implement `{$expected}` derives from here
|
||||
|
||||
trait_selection_dump_vtable_entries = vtable entries for `{$trait_ref}`: {$entries}
|
||||
|
||||
trait_selection_empty_on_clause_in_rustc_on_unimplemented = empty `on`-clause in `#[rustc_on_unimplemented]`
|
||||
|
@ -4,7 +4,7 @@ use rustc_errors::{
|
||||
SubdiagnosticMessage,
|
||||
};
|
||||
use rustc_macros::Diagnostic;
|
||||
use rustc_middle::ty::{self, PolyTraitRef, Ty};
|
||||
use rustc_middle::ty::{self, ClosureKind, PolyTraitRef, Ty};
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
@ -131,3 +131,37 @@ impl AddToDiagnostic for AdjustSignatureBorrow {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(trait_selection_closure_kind_mismatch, code = "E0525")]
|
||||
pub struct ClosureKindMismatch {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub closure_span: Span,
|
||||
pub expected: ClosureKind,
|
||||
pub found: ClosureKind,
|
||||
#[label(trait_selection_closure_kind_requirement)]
|
||||
pub cause_span: Span,
|
||||
|
||||
#[subdiagnostic]
|
||||
pub fn_once_label: Option<ClosureFnOnceLabel>,
|
||||
|
||||
#[subdiagnostic]
|
||||
pub fn_mut_label: Option<ClosureFnMutLabel>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[label(trait_selection_closure_fn_once_label)]
|
||||
pub struct ClosureFnOnceLabel {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub place: String,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[label(trait_selection_closure_fn_mut_label)]
|
||||
pub struct ClosureFnMutLabel {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub place: String,
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ use super::{
|
||||
ObligationCauseCode, ObligationCtxt, OutputTypeParameterMismatch, Overflow,
|
||||
PredicateObligation, SelectionError, TraitNotObjectSafe,
|
||||
};
|
||||
use crate::errors::{ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch};
|
||||
use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
|
||||
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use crate::infer::{self, InferCtxt};
|
||||
@ -3110,27 +3111,6 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
) -> UnsatisfiedConst {
|
||||
let unsatisfied_const = UnsatisfiedConst(false);
|
||||
// FIXME(effects)
|
||||
/* if trait_predicate.is_const_if_const() {
|
||||
let non_const_predicate = trait_ref.without_const();
|
||||
let non_const_obligation = Obligation {
|
||||
cause: obligation.cause.clone(),
|
||||
param_env: obligation.param_env,
|
||||
predicate: non_const_predicate.to_predicate(self.tcx),
|
||||
recursion_depth: obligation.recursion_depth,
|
||||
};
|
||||
if self.predicate_may_hold(&non_const_obligation) {
|
||||
unsatisfied_const = UnsatisfiedConst(true);
|
||||
err.span_note(
|
||||
span,
|
||||
format!(
|
||||
"the trait `{}` is implemented for `{}`, \
|
||||
but that implementation is not `const`",
|
||||
non_const_predicate.print_modifiers_and_trait_path(),
|
||||
trait_ref.skip_binder().self_ty(),
|
||||
),
|
||||
);
|
||||
}
|
||||
} */
|
||||
unsatisfied_const
|
||||
}
|
||||
|
||||
@ -3142,24 +3122,15 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
kind: ty::ClosureKind,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
let closure_span = self.tcx.def_span(closure_def_id);
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
closure_span,
|
||||
E0525,
|
||||
"expected a closure that implements the `{}` trait, \
|
||||
but this closure only implements `{}`",
|
||||
kind,
|
||||
found_kind
|
||||
);
|
||||
|
||||
err.span_label(
|
||||
let mut err = ClosureKindMismatch {
|
||||
closure_span,
|
||||
format!("this closure implements `{found_kind}`, not `{kind}`"),
|
||||
);
|
||||
err.span_label(
|
||||
obligation.cause.span,
|
||||
format!("the requirement to implement `{kind}` derives from here"),
|
||||
);
|
||||
expected: kind,
|
||||
found: found_kind,
|
||||
cause_span: obligation.cause.span,
|
||||
fn_once_label: None,
|
||||
fn_mut_label: None,
|
||||
};
|
||||
|
||||
// Additional context information explaining why the closure only implements
|
||||
// a particular trait.
|
||||
@ -3167,30 +3138,22 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
let hir_id = self.tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local());
|
||||
match (found_kind, typeck_results.closure_kind_origins().get(hir_id)) {
|
||||
(ty::ClosureKind::FnOnce, Some((span, place))) => {
|
||||
err.span_label(
|
||||
*span,
|
||||
format!(
|
||||
"closure is `FnOnce` because it moves the \
|
||||
variable `{}` out of its environment",
|
||||
ty::place_to_string_for_capture(self.tcx, place)
|
||||
),
|
||||
);
|
||||
err.fn_once_label = Some(ClosureFnOnceLabel {
|
||||
span: *span,
|
||||
place: ty::place_to_string_for_capture(self.tcx, &place),
|
||||
})
|
||||
}
|
||||
(ty::ClosureKind::FnMut, Some((span, place))) => {
|
||||
err.span_label(
|
||||
*span,
|
||||
format!(
|
||||
"closure is `FnMut` because it mutates the \
|
||||
variable `{}` here",
|
||||
ty::place_to_string_for_capture(self.tcx, place)
|
||||
),
|
||||
);
|
||||
err.fn_mut_label = Some(ClosureFnMutLabel {
|
||||
span: *span,
|
||||
place: ty::place_to_string_for_capture(self.tcx, &place),
|
||||
})
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
err
|
||||
self.tcx.sess.create_err(err)
|
||||
}
|
||||
|
||||
fn report_type_parameter_mismatch_cyclic_type_error(
|
||||
|
@ -2743,6 +2743,12 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
}
|
||||
ObligationCauseCode::BindingObligation(item_def_id, span)
|
||||
| ObligationCauseCode::ExprBindingObligation(item_def_id, span, ..) => {
|
||||
if self.tcx.is_diagnostic_item(sym::Send, item_def_id)
|
||||
|| self.tcx.lang_items().sync_trait() == Some(item_def_id)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
let item_name = tcx.def_path_str(item_def_id);
|
||||
let short_item_name = with_forced_trimmed_paths!(tcx.def_path_str(item_def_id));
|
||||
let mut multispan = MultiSpan::from(span);
|
||||
|
@ -9,6 +9,7 @@ use rustc_session::config::OptLevel;
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_target::abi::call::{
|
||||
ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, Reg, RegKind,
|
||||
RiscvInterruptKind,
|
||||
};
|
||||
use rustc_target::abi::*;
|
||||
use rustc_target::spec::abi::Abi as SpecAbi;
|
||||
@ -193,6 +194,8 @@ fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi) -> Conv {
|
||||
AmdGpuKernel => Conv::AmdGpuKernel,
|
||||
AvrInterrupt => Conv::AvrInterrupt,
|
||||
AvrNonBlockingInterrupt => Conv::AvrNonBlockingInterrupt,
|
||||
RiscvInterruptM => Conv::RiscvInterrupt { kind: RiscvInterruptKind::Machine },
|
||||
RiscvInterruptS => Conv::RiscvInterrupt { kind: RiscvInterruptKind::Supervisor },
|
||||
Wasm => Conv::C,
|
||||
|
||||
// These API constants ought to be more specific...
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user