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:
bors 2023-08-11 12:51:25 +00:00
commit 6276e5ad14
439 changed files with 4256 additions and 3040 deletions

View File

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

View File

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

View File

@ -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",

View File

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

View File

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

View File

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

View File

@ -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) => {

View File

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

View File

@ -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()

View File

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

View File

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

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

View File

@ -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",

View File

@ -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",

View File

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

View File

@ -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")

View File

@ -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![],
}

View File

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

View File

@ -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) {

View File

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

View File

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

View File

@ -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`.

View File

@ -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('-', "_")),

View File

@ -11,7 +11,7 @@
thread_local
)]
#![no_core]
#![allow(dead_code)]
#![allow(dead_code, internal_features)]
#[lang = "sized"]
pub trait Sized {}

View File

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

View File

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

View File

@ -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",

View File

@ -1,3 +1,3 @@
[toolchain]
channel = "nightly-2023-07-22"
channel = "nightly-2023-08-08"
components = ["rust-src", "rustc-dev", "llvm-tools"]

View File

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

View File

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

View File

@ -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 => {

View File

@ -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",

View File

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

View File

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

View File

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

View File

@ -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)]

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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(),

View File

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

View File

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

View File

@ -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 });
}
}
}
_ => {}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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!(),
}
}

View File

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

View File

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

View File

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

View File

@ -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,
) {

View File

@ -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()

View File

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

View File

@ -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()),

View File

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

View File

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

View File

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

View File

@ -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) {

View File

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

View File

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

View File

@ -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,
);

View File

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

View File

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

View File

@ -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)]

View File

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

View File

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

View File

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

View File

@ -30,6 +30,8 @@ fn abi_can_unwind(abi: Abi) -> bool {
| EfiApi
| AvrInterrupt
| AvrNonBlockingInterrupt
| RiscvInterruptM
| RiscvInterruptS
| CCmseNonSecureCall
| Wasm
| RustIntrinsic

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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() {

View File

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

View File

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

View File

@ -326,6 +326,7 @@ symbols! {
abi_efiapi,
abi_msp430_interrupt,
abi_ptx,
abi_riscv_interrupt,
abi_sysv64,
abi_thiscall,
abi_unadjusted,

View File

@ -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.")),
}
}

View File

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

View File

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

View 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,
}
}

View File

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

View File

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

View File

@ -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(()))

View 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()
}
}

View File

@ -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]`

View File

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

View File

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

View File

@ -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);

View File

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