Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions compiler/rustc_codegen_ssa/src/back/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ mod symbol_edit;
pub mod symbol_export;
pub mod write;

pub use symbol_export::{exported_non_generic_symbols_helper, reachable_non_generics_helper};

/// The target triple depends on the deployment target, and is required to
/// enable features such as cross-language LTO, and for picking the right
/// Mach-O commands.
Expand Down
12 changes: 12 additions & 0 deletions compiler/rustc_codegen_ssa/src/back/symbol_export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap<S
return Default::default();
}

reachable_non_generics_helper(tcx)
}

/// Exposed separately *without* the "should codegen" check so Miri can access it.
pub fn reachable_non_generics_helper(tcx: TyCtxt<'_>) -> DefIdMap<SymbolExportInfo> {
let is_compiler_builtins = tcx.is_compiler_builtins(LOCAL_CRATE);

let mut reachable_non_generics: DefIdMap<_> = tcx
Expand Down Expand Up @@ -176,6 +181,13 @@ fn exported_non_generic_symbols_provider_local<'tcx>(
return &[];
}

exported_non_generic_symbols_helper(tcx)
}

/// Exposed separately *without* the "should codegen" check so Miri can access it.
pub fn exported_non_generic_symbols_helper<'tcx>(
tcx: TyCtxt<'tcx>,
) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] {
// FIXME: Sorting this is unnecessary since we are sorting later anyway.
// Can we skip the later sorting?
let sorted = tcx.with_stable_hashing_context(|mut hcx| {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4769,7 +4769,7 @@ pub enum RestrictionKind<'hir> {
/// explicitly to allow unsafe operations.
#[derive(Copy, Clone, Debug, StableHash, PartialEq, Eq)]
pub enum HeaderSafety {
/// A safe function annotated with `#[target_features]`.
/// A safe function annotated with `#[target_feature(..)]`.
/// The type system treats this function as an unsafe function,
/// but safety checking will check this enum to treat it as safe
/// and allowing calling other safe target feature functions with
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_middle/src/ty/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@ impl<'tcx> TypeError<'tcx> {
}
TypeError::IntrinsicCast => "cannot coerce intrinsics to function pointers".into(),
TypeError::TargetFeatureCast(_) => {
"cannot coerce functions with `#[target_feature]` to safe function pointers".into()
"cannot coerce functions with `#[target_feature(..)]` to safe function pointers"
.into()
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/print/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -789,7 +789,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
let mut sig =
self.tcx().fn_sig(def_id).instantiate(self.tcx(), args).skip_norm_wip();
if self.tcx().codegen_fn_attrs(def_id).safe_target_features {
write!(self, "#[target_features] ")?;
write!(self, "#[target_feature(..)] ")?;
sig = sig.map_bound(|mut sig| {
sig.fn_sig_kind = sig.fn_sig_kind.set_safety(hir::Safety::Safe);
sig
Expand Down
9 changes: 1 addition & 8 deletions compiler/rustc_next_trait_solver/src/solve/search_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ where
response_no_constraints(cx, input, Certainty::overflow(true))
}

const FIXPOINT_OVERFLOW_AMBIGUITY_KIND: Certainty = Certainty::overflow(false);
fn fixpoint_overflow_result(
cx: I,
input: CanonicalInput<I>,
Expand All @@ -126,14 +127,6 @@ where
})
}

fn propagate_ambiguity(
cx: I,
for_input: CanonicalInput<I>,
certainty: Certainty,
) -> (QueryResult<I>, AccessedOpaques<I>) {
response_no_constraints(cx, for_input, certainty)
}

fn compute_goal(
search_graph: &mut SearchGraph<D>,
cx: I,
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_passes/src/reachable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,8 @@ fn has_custom_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
// FIXME(nbdd0121): `#[used]` are marked as reachable here so it's picked up by
// `linked_symbols` in cg_ssa. They won't be exported in binary or cdylib due to their
// `SymbolExportLevel::Rust` export level but may end up being exported in dylibs.
// Also note that Miri is relying on this to be able to find private `link_section` statics
// across all crates.
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER)
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
// Right now, the only way to get "foreign item symbol aliases" is by being an EII-implementation.
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_target/src/target_features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1219,7 +1219,7 @@ impl Target {
/// These features are checked against the target features reported by LLVM based on
/// `-Ctarget-cpu` and `-Ctarget-features`. Constraint violations result in a warning.
///
/// We also check features enabled via `#[target_features]` (and here, constraint violations
/// We also check features enabled via `#[target_feature(..)]` (and here, constraint violations
/// emit a hard error), including features enabled indirectly via implications -- but if LLVM
/// considers more features to be implied than we do, that could bypass this check!
pub fn abi_required_features(&self) -> FeatureConstraints {
Expand Down
36 changes: 18 additions & 18 deletions compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -773,17 +773,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let (lt1, sig1) = get_lifetimes(sig1);
let (lt2, sig2) = get_lifetimes(sig2);

// #[target_features] for<'a> unsafe extern "C" fn(&'a T) -> &'a T
// #[target_feature(..)] for<'a> unsafe extern "C" fn(&'a T) -> &'a T
let mut values =
(DiagStyledString::normal("".to_string()), DiagStyledString::normal("".to_string()));

// #[target_features] for<'a> unsafe extern "C" fn(&'a T) -> &'a T
// ^^^^^^^^^^^^^^^^^^
// #[target_feature(..)] for<'a> unsafe extern "C" fn(&'a T) -> &'a T
// ^^^^^^^^^^^^^^^^^^^^^
let fn_item_prefix_and_safety = |fn_def, sig: ty::FnSig<'_>| match fn_def {
None => ("", sig.safety().prefix_str()),
Some((did, _)) => {
if self.tcx.codegen_fn_attrs(did).safe_target_features {
("#[target_features] ", "")
("#[target_feature(..)] ", "")
} else {
("", sig.safety().prefix_str())
}
Expand All @@ -794,33 +794,33 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
values.0.push(prefix1, prefix1 != prefix2);
values.1.push(prefix2, prefix1 != prefix2);

// #[target_features] for<'a> unsafe extern "C" fn(&'a T) -> &'a T
// ^^^^^^^^
// #[target_feature(..)] for<'a> unsafe extern "C" fn(&'a T) -> &'a T
// ^^^^^^^^
let lifetime_diff = lt1 != lt2;
values.0.push(lt1, lifetime_diff);
values.1.push(lt2, lifetime_diff);

// #[target_features] for<'a> unsafe extern "C" fn(&'a T) -> &'a T
// ^^^^^^
// #[target_feature(..)] for<'a> unsafe extern "C" fn(&'a T) -> &'a T
// ^^^^^^
values.0.push(safety1, safety1 != safety2);
values.1.push(safety2, safety1 != safety2);

// #[target_features] for<'a> unsafe extern "C" fn(&'a T) -> &'a T
// ^^^^^^^^^^
// #[target_feature(..)] for<'a> unsafe extern "C" fn(&'a T) -> &'a T
// ^^^^^^^^^^
if sig1.abi() != ExternAbi::Rust {
values.0.push(format!("extern {} ", sig1.abi()), sig1.abi() != sig2.abi());
}
if sig2.abi() != ExternAbi::Rust {
values.1.push(format!("extern {} ", sig2.abi()), sig1.abi() != sig2.abi());
}

// #[target_features] for<'a> unsafe extern "C" fn(&'a T) -> &'a T
// ^^^
// #[target_feature(..)] for<'a> unsafe extern "C" fn(&'a T) -> &'a T
// ^^^
values.0.push_normal("fn(");
values.1.push_normal("fn(");

// #[target_features] for<'a> unsafe extern "C" fn(&'a T) -> &'a T
// ^^^^^
// #[target_feature(..)] for<'a> unsafe extern "C" fn(&'a T) -> &'a T
// ^^^^^
let len1 = sig1.inputs().len();
let len2 = sig2.inputs().len();
let splatted_arg_index1 = sig1.splatted().map(usize::from);
Expand Down Expand Up @@ -868,13 +868,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
values.1.push("...", !sig1.c_variadic());
}

// #[target_features] for<'a> unsafe extern "C" fn(&'a T) -> &'a T
// ^
// #[target_feature(..)] for<'a> unsafe extern "C" fn(&'a T) -> &'a T
// ^
values.0.push_normal(")");
values.1.push_normal(")");

// #[target_features] for<'a> unsafe extern "C" fn(&'a T) -> &'a T
// ^^^^^^^^
// #[target_feature(..)] for<'a> unsafe extern "C" fn(&'a T) -> &'a T
// ^^^^^^^^
let output1 = sig1.output();
let output2 = sig2.output();
let (x1, x2) = self.cmp(output1, output2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -621,9 +621,9 @@ impl<T> Trait<T> for X {
TypeError::TargetFeatureCast(def_id) => {
let target_spans = find_attr!(tcx, def_id, TargetFeature{attr_span: span, was_forced: false, ..} => *span);
diag.note(
"functions with `#[target_feature]` can only be coerced to `unsafe` function pointers"
"functions with `#[target_feature(..)]` can only be coerced to `unsafe` function pointers"
);
diag.span_labels(target_spans, "`#[target_feature]` added here");
diag.span_labels(target_spans, "`#[target_feature(..)]` added here");
}
_ => {}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
};
if is_fn_trait && is_target_feature_fn {
err.note(
"`#[target_feature]` functions do not implement the `Fn` traits",
"`#[target_feature(..)]` functions do not implement the `Fn` traits",
);
err.note(
"try casting the function to a `fn` pointer or wrapping it in a closure",
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_type_ir/src/interner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -680,7 +680,7 @@ impl<T, R, E> CollectAndApply<T, R> for Result<T, E> {
impl<I: Interner> search_graph::Cx for I {
type Input = CanonicalInput<I>;
type Result = (QueryResult<I>, AccessedOpaques<I>);
type AmbiguityInfo = Certainty;
type AmbiguityKind = Certainty;

type DepNodeIndex = I::DepNodeIndex;
type Tracked<T: Debug + Clone> = I::Tracked<T>;
Expand Down
55 changes: 24 additions & 31 deletions compiler/rustc_type_ir/src/search_graph/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ pub use global_cache::GlobalCache;
pub trait Cx: Copy {
type Input: Debug + Eq + Hash + Copy;
type Result: Debug + Eq + Hash + Copy;
type AmbiguityInfo: Debug + Eq + Hash + Copy;
type AmbiguityKind: Debug + Eq + Hash + Copy;

type DepNodeIndex;
type Tracked<T: Debug + Clone>: Debug;
Expand Down Expand Up @@ -92,19 +92,16 @@ pub trait Delegate: Sized {
cx: Self::Cx,
input: <Self::Cx as Cx>::Input,
) -> <Self::Cx as Cx>::Result;

const FIXPOINT_OVERFLOW_AMBIGUITY_KIND: <Self::Cx as Cx>::AmbiguityKind;
fn fixpoint_overflow_result(
cx: Self::Cx,
input: <Self::Cx as Cx>::Input,
) -> <Self::Cx as Cx>::Result;

fn is_ambiguous_result(
result: <Self::Cx as Cx>::Result,
) -> Option<<Self::Cx as Cx>::AmbiguityInfo>;
fn propagate_ambiguity(
cx: Self::Cx,
for_input: <Self::Cx as Cx>::Input,
ambiguity_info: <Self::Cx as Cx>::AmbiguityInfo,
) -> <Self::Cx as Cx>::Result;
) -> Option<<Self::Cx as Cx>::AmbiguityKind>;

fn compute_goal(
search_graph: &mut SearchGraph<Self>,
Expand Down Expand Up @@ -955,8 +952,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
#[derive_where(Debug; X: Cx)]
enum RebaseReason<X: Cx> {
NoCycleUsages,
Ambiguity(X::AmbiguityInfo),
Overflow,
Ambiguity(X::AmbiguityKind),
/// We've actually reached a fixpoint.
///
/// This either happens in the first evaluation step for the cycle head.
Expand Down Expand Up @@ -987,10 +983,9 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D, X> {
/// cache entries to also be ambiguous. This causes some undesirable ambiguity for nested
/// goals whose result doesn't actually depend on this cycle head, but that's acceptable
/// to me.
#[instrument(level = "trace", skip(self, cx))]
#[instrument(level = "trace", skip(self))]
fn rebase_provisional_cache_entries(
&mut self,
cx: X,
stack_entry: &StackEntry<X>,
rebase_reason: RebaseReason<X>,
) {
Expand Down Expand Up @@ -1065,18 +1060,22 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D, X> {
}

// The provisional cache entry does depend on the provisional result
// of the popped cycle head. We need to mutate the result of our
// provisional cache entry in case we did not reach a fixpoint.
// of the popped cycle head. In case we didn't actually reach a fixpoint,
// we must not keep potentially incorrect provisional cache entries around.
match rebase_reason {
// If the cycle head does not actually depend on itself, then
// the provisional result used by the provisional cache entry
// is not actually equal to the final provisional result. We
// need to discard the provisional cache entry in this case.
RebaseReason::NoCycleUsages => return false,
RebaseReason::Ambiguity(info) => {
*result = D::propagate_ambiguity(cx, input, info);
// If we avoid rerunning a goal due to ambiguity, we only keep provisional
// results which depend on that cycle head if these are already ambiguous
// themselves.
RebaseReason::Ambiguity(kind) => {
if !D::is_ambiguous_result(*result).is_some_and(|k| k == kind) {
return false;
}
}
RebaseReason::Overflow => *result = D::fixpoint_overflow_result(cx, input),
RebaseReason::ReachedFixpoint(None) => {}
RebaseReason::ReachedFixpoint(Some(path_kind)) => {
if !popped_head.usages.is_single(path_kind) {
Expand Down Expand Up @@ -1380,17 +1379,12 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D, X> {
// final result is equal to the initial response for that case.
if let Ok(fixpoint) = self.reached_fixpoint(&stack_entry, usages, result) {
self.rebase_provisional_cache_entries(
cx,
&stack_entry,
RebaseReason::ReachedFixpoint(fixpoint),
);
return EvaluationResult::finalize(stack_entry, encountered_overflow, result);
} else if usages.is_empty() {
self.rebase_provisional_cache_entries(
cx,
&stack_entry,
RebaseReason::NoCycleUsages,
);
self.rebase_provisional_cache_entries(&stack_entry, RebaseReason::NoCycleUsages);
return EvaluationResult::finalize(stack_entry, encountered_overflow, result);
}

Expand All @@ -1399,19 +1393,15 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D, X> {
// response in the next iteration in this case. These changes would
// likely either be caused by incompleteness or can change the maybe
// cause from ambiguity to overflow. Returning ambiguity always
// preserves soundness and completeness even if the goal is be known
// to succeed or fail.
// preserves soundness and completeness even if the goal could
// otherwise succeed or fail.
//
// This prevents exponential blowup affecting multiple major crates.
// As we only get to this branch if we haven't yet reached a fixpoint,
// we also taint all provisional cache entries which depend on the
// current goal.
if let Some(info) = D::is_ambiguous_result(result) {
self.rebase_provisional_cache_entries(
cx,
&stack_entry,
RebaseReason::Ambiguity(info),
);
if let Some(kind) = D::is_ambiguous_result(result) {
self.rebase_provisional_cache_entries(&stack_entry, RebaseReason::Ambiguity(kind));
return EvaluationResult::finalize(stack_entry, encountered_overflow, result);
};

Expand All @@ -1421,7 +1411,10 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D, X> {
if i >= D::FIXPOINT_STEP_LIMIT {
debug!("canonical cycle overflow");
let result = D::fixpoint_overflow_result(cx, input);
self.rebase_provisional_cache_entries(cx, &stack_entry, RebaseReason::Overflow);
self.rebase_provisional_cache_entries(
&stack_entry,
RebaseReason::Ambiguity(D::FIXPOINT_OVERFLOW_AMBIGUITY_KIND),
);
return EvaluationResult::finalize(stack_entry, encountered_overflow, result);
}

Expand Down
4 changes: 4 additions & 0 deletions src/bootstrap/src/core/build_steps/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -839,6 +839,10 @@ impl Step for CargoMiri {
SourceType::Submodule,
&[],
);
// Run subcrate tests as well.
cargo.arg("--workspace");
// Some tests need isolation disabled.
cargo.env("MIRIFLAGS", "-Zmiri-disable-isolation");

// If we are testing stage 2+ cargo miri, make sure that it works with the in-tree cargo.
// We want to do this *somewhere* to ensure that Miri + nightly cargo actually works.
Expand Down
Loading
Loading