Skip to content

Commit

Permalink
Auto merge of rust-lang#3851 - rust-lang:rustup-2024-08-29, r=RalfJung
Browse files Browse the repository at this point in the history
Automatic Rustup
  • Loading branch information
bors committed Aug 29, 2024
2 parents 9ad0f65 + b5be3ab commit ad7a1aa
Show file tree
Hide file tree
Showing 192 changed files with 1,474 additions and 818 deletions.
7 changes: 4 additions & 3 deletions compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use rustc_middle::mir::coverage::{
CodeRegion, ConditionInfo, CounterId, CovTerm, DecisionInfo, ExpressionId, MappingKind,
ConditionInfo, CounterId, CovTerm, DecisionInfo, ExpressionId, MappingKind, SourceRegion,
};

/// Must match the layout of `LLVMRustCounterKind`.
Expand Down Expand Up @@ -236,9 +236,10 @@ impl CounterMappingRegion {
pub(crate) fn from_mapping(
mapping_kind: &MappingKind,
local_file_id: u32,
code_region: &CodeRegion,
source_region: &SourceRegion,
) -> Self {
let &CodeRegion { file_name: _, start_line, start_col, end_line, end_col } = code_region;
let &SourceRegion { file_name: _, start_line, start_col, end_line, end_col } =
source_region;
match *mapping_kind {
MappingKind::Code(term) => Self::code_region(
Counter::from_term(term),
Expand Down
12 changes: 6 additions & 6 deletions compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxIndexSet;
use rustc_index::bit_set::BitSet;
use rustc_middle::mir::coverage::{
CodeRegion, CounterId, CovTerm, Expression, ExpressionId, FunctionCoverageInfo, Mapping,
MappingKind, Op,
CounterId, CovTerm, Expression, ExpressionId, FunctionCoverageInfo, Mapping, MappingKind, Op,
SourceRegion,
};
use rustc_middle::ty::Instance;
use rustc_span::Symbol;
Expand Down Expand Up @@ -201,7 +201,7 @@ impl<'tcx> FunctionCoverage<'tcx> {

/// Returns an iterator over all filenames used by this function's mappings.
pub(crate) fn all_file_names(&self) -> impl Iterator<Item = Symbol> + Captures<'_> {
self.function_coverage_info.mappings.iter().map(|mapping| mapping.code_region.file_name)
self.function_coverage_info.mappings.iter().map(|mapping| mapping.source_region.file_name)
}

/// Convert this function's coverage expression data into a form that can be
Expand Down Expand Up @@ -230,12 +230,12 @@ impl<'tcx> FunctionCoverage<'tcx> {
/// that will be used by `mapgen` when preparing for FFI.
pub(crate) fn counter_regions(
&self,
) -> impl Iterator<Item = (MappingKind, &CodeRegion)> + ExactSizeIterator {
) -> impl Iterator<Item = (MappingKind, &SourceRegion)> + ExactSizeIterator {
self.function_coverage_info.mappings.iter().map(move |mapping| {
let Mapping { kind, code_region } = mapping;
let Mapping { kind, source_region } = mapping;
let kind =
kind.map_terms(|term| if self.is_zero_term(term) { CovTerm::Zero } else { term });
(kind, code_region)
(kind, source_region)
})
}

Expand Down
125 changes: 115 additions & 10 deletions compiler/rustc_codegen_ssa/src/codegen_attrs.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use rustc_ast::{ast, attr, MetaItemKind, NestedMetaItem};
use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::codes::*;
use rustc_errors::{struct_span_code_err, DiagMessage, SubdiagMessage};
use rustc_hir as hir;
Expand All @@ -8,7 +9,7 @@ use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS;
use rustc_hir::{lang_items, LangItem};
use rustc_middle::middle::codegen_fn_attrs::{
CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry,
CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, TargetFeature,
};
use rustc_middle::mir::mono::Linkage;
use rustc_middle::query::Providers;
Expand All @@ -17,6 +18,7 @@ use rustc_session::lint;
use rustc_session::parse::feature_err;
use rustc_span::symbol::Ident;
use rustc_span::{sym, Span};
use rustc_target::abi::VariantIdx;
use rustc_target::spec::{abi, SanitizerSet};

use crate::errors;
Expand Down Expand Up @@ -78,23 +80,26 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
let mut link_ordinal_span = None;
let mut no_sanitize_span = None;

let fn_sig_outer = || {
use DefKind::*;

let def_kind = tcx.def_kind(did);
if let Fn | AssocFn | Variant | Ctor(..) = def_kind { Some(tcx.fn_sig(did)) } else { None }
};

for attr in attrs.iter() {
// In some cases, attribute are only valid on functions, but it's the `check_attr`
// pass that check that they aren't used anywhere else, rather this module.
// In these cases, we bail from performing further checks that are only meaningful for
// functions (such as calling `fn_sig`, which ICEs if given a non-function). We also
// report a delayed bug, just in case `check_attr` isn't doing its job.
let fn_sig = || {
use DefKind::*;

let def_kind = tcx.def_kind(did);
if let Fn | AssocFn | Variant | Ctor(..) = def_kind {
Some(tcx.fn_sig(did))
} else {
let sig = fn_sig_outer();
if sig.is_none() {
tcx.dcx()
.span_delayed_bug(attr.span, "this attribute can only be applied to functions");
None
}
sig
};

let Some(Ident { name, .. }) = attr.ident() else {
Expand Down Expand Up @@ -613,7 +618,93 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
}
}

// If a function uses #[target_feature] it can't be inlined into general
if let Some(sig) = fn_sig_outer() {
// Collect target features from types reachable from arguments.
// We define a type as "reachable" if:
// - it is a function argument
// - it is a field of a reachable struct
// - there is a reachable reference to it
// FIXME(struct_target_features): we may want to cache the result of this computation.
let mut visited_types = FxHashSet::default();
let mut reachable_types: Vec<_> = sig.skip_binder().inputs().skip_binder().to_owned();
let mut additional_tf = vec![];

while let Some(ty) = reachable_types.pop() {
if visited_types.contains(&ty) {
continue;
}
visited_types.insert(ty);
match ty.kind() {
ty::Alias(..) => {
if let Ok(t) =
tcx.try_normalize_erasing_regions(tcx.param_env(did.to_def_id()), ty)
{
reachable_types.push(t)
}
}

ty::Ref(_, inner, _) => reachable_types.push(*inner),
ty::Tuple(tys) => reachable_types.extend(tys.iter()),
ty::Adt(adt_def, args) => {
additional_tf.extend_from_slice(tcx.struct_target_features(adt_def.did()));
// This only recurses into structs as i.e. an Option<TargetFeature> is an ADT
// that doesn't actually always contain a TargetFeature.
if adt_def.is_struct() {
reachable_types.extend(
adt_def
.variant(VariantIdx::from_usize(0))
.fields
.iter()
.map(|field| field.ty(tcx, args)),
);
}
}
ty::Bool
| ty::Char
| ty::Int(..)
| ty::Uint(..)
| ty::Float(..)
| ty::Foreign(..)
| ty::Str
| ty::Array(..)
| ty::Pat(..)
| ty::Slice(..)
| ty::RawPtr(..)
| ty::FnDef(..)
| ty::FnPtr(..)
| ty::Dynamic(..)
| ty::Closure(..)
| ty::CoroutineClosure(..)
| ty::Coroutine(..)
| ty::CoroutineWitness(..)
| ty::Never
| ty::Param(..)
| ty::Bound(..)
| ty::Placeholder(..)
| ty::Infer(..)
| ty::Error(..) => (),
}
}

// FIXME(struct_target_features): is this really necessary?
if !additional_tf.is_empty() && sig.skip_binder().abi() != abi::Abi::Rust {
tcx.dcx().span_err(
tcx.hir().span(tcx.local_def_id_to_hir_id(did)),
"cannot use a struct with target features in a function with non-Rust ABI",
);
}
if !additional_tf.is_empty() && codegen_fn_attrs.inline == InlineAttr::Always {
tcx.dcx().span_err(
tcx.hir().span(tcx.local_def_id_to_hir_id(did)),
"cannot use a struct with target features in a #[inline(always)] function",
);
}
codegen_fn_attrs
.target_features
.extend(additional_tf.iter().map(|tf| TargetFeature { implied: true, ..*tf }));
}

// If a function uses non-default target_features it can't be inlined into general
// purpose functions as they wouldn't have the right target features
// enabled. For that reason we also forbid #[inline(always)] as it can't be
// respected.
Expand Down Expand Up @@ -758,6 +849,20 @@ fn check_link_name_xor_ordinal(
}
}

fn struct_target_features(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &[TargetFeature] {
let mut features = vec![];
let supported_features = tcx.supported_target_features(LOCAL_CRATE);
for attr in tcx.get_attrs(def_id, sym::target_feature) {
from_target_feature(tcx, attr, supported_features, &mut features);
}
tcx.arena.alloc_slice(&features)
}

pub fn provide(providers: &mut Providers) {
*providers = Providers { codegen_fn_attrs, should_inherit_track_caller, ..*providers };
*providers = Providers {
codegen_fn_attrs,
should_inherit_track_caller,
struct_target_features,
..*providers
};
}
3 changes: 0 additions & 3 deletions compiler/rustc_const_eval/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -402,9 +402,6 @@ const_eval_unallowed_mutable_refs =
const_eval_unallowed_op_in_const_context =
{$msg}
const_eval_unavailable_target_features_for_fn =
calling a function that requires unavailable target features: {$unavailable_feats}
const_eval_uninhabited_enum_variant_read =
read discriminant of an uninhabited enum variant
const_eval_uninhabited_enum_variant_written =
Expand Down
44 changes: 7 additions & 37 deletions compiler/rustc_const_eval/src/interpret/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,34 +311,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
Ok(())
}

fn check_fn_target_features(&self, instance: ty::Instance<'tcx>) -> InterpResult<'tcx, ()> {
// Calling functions with `#[target_feature]` is not unsafe on WASM, see #84988
let attrs = self.tcx.codegen_fn_attrs(instance.def_id());
if !self.tcx.sess.target.is_like_wasm
&& attrs
.target_features
.iter()
.any(|feature| !self.tcx.sess.target_features.contains(&feature.name))
{
throw_ub_custom!(
fluent::const_eval_unavailable_target_features_for_fn,
unavailable_feats = attrs
.target_features
.iter()
.filter(|&feature| !feature.implied
&& !self.tcx.sess.target_features.contains(&feature.name))
.fold(String::new(), |mut s, feature| {
if !s.is_empty() {
s.push_str(", ");
}
s.push_str(feature.name.as_str());
s
}),
);
}
Ok(())
}

/// The main entry point for creating a new stack frame: performs ABI checks and initializes
/// arguments.
#[instrument(skip(self), level = "trace")]
Expand All @@ -360,20 +332,18 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
throw_unsup_format!("calling a c-variadic function is not supported");
}

if M::enforce_abi(self) {
if caller_fn_abi.conv != callee_fn_abi.conv {
throw_ub_custom!(
fluent::const_eval_incompatible_calling_conventions,
callee_conv = format!("{:?}", callee_fn_abi.conv),
caller_conv = format!("{:?}", caller_fn_abi.conv),
)
}
if caller_fn_abi.conv != callee_fn_abi.conv {
throw_ub_custom!(
fluent::const_eval_incompatible_calling_conventions,
callee_conv = format!("{:?}", callee_fn_abi.conv),
caller_conv = format!("{:?}", caller_fn_abi.conv),
)
}

// Check that all target features required by the callee (i.e., from
// the attribute `#[target_feature(enable = ...)]`) are enabled at
// compile time.
self.check_fn_target_features(instance)?;
M::check_fn_target_features(self, instance)?;

if !callee_fn_abi.can_unwind {
// The callee cannot unwind, so force the `Unreachable` unwind handling.
Expand Down
10 changes: 5 additions & 5 deletions compiler/rustc_const_eval/src/interpret/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -684,19 +684,19 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
assert!(layout.is_sized());

let get_bytes = |this: &InterpCx<'tcx, M>,
op: &OpTy<'tcx, <M as Machine<'tcx>>::Provenance>,
size|
op: &OpTy<'tcx, <M as Machine<'tcx>>::Provenance>|
-> InterpResult<'tcx, &[u8]> {
let ptr = this.read_pointer(op)?;
let Some(alloc_ref) = self.get_ptr_alloc(ptr, size)? else {
this.check_ptr_align(ptr, layout.align.abi)?;
let Some(alloc_ref) = self.get_ptr_alloc(ptr, layout.size)? else {
// zero-sized access
return Ok(&[]);
};
alloc_ref.get_bytes_strip_provenance()
};

let lhs_bytes = get_bytes(self, lhs, layout.size)?;
let rhs_bytes = get_bytes(self, rhs, layout.size)?;
let lhs_bytes = get_bytes(self, lhs)?;
let rhs_bytes = get_bytes(self, rhs)?;
Ok(Scalar::from_bool(lhs_bytes == rhs_bytes))
}
}
32 changes: 27 additions & 5 deletions compiler/rustc_const_eval/src/interpret/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,11 +173,6 @@ pub trait Machine<'tcx>: Sized {
false
}

/// Whether function calls should be [ABI](CallAbi)-checked.
fn enforce_abi(_ecx: &InterpCx<'tcx, Self>) -> bool {
true
}

/// Whether Assert(OverflowNeg) and Assert(Overflow) MIR terminators should actually
/// check for overflow.
fn ignore_optional_overflow_checks(_ecx: &InterpCx<'tcx, Self>) -> bool;
Expand Down Expand Up @@ -238,6 +233,13 @@ pub trait Machine<'tcx>: Sized {
unwind: mir::UnwindAction,
) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>>;

/// Check whether the given function may be executed on the current machine, in terms of the
/// target features is requires.
fn check_fn_target_features(
_ecx: &InterpCx<'tcx, Self>,
_instance: ty::Instance<'tcx>,
) -> InterpResult<'tcx>;

/// Called to evaluate `Assert` MIR terminators that trigger a panic.
fn assert_panic(
ecx: &mut InterpCx<'tcx, Self>,
Expand Down Expand Up @@ -280,6 +282,9 @@ pub trait Machine<'tcx>: Sized {
Ok(())
}

/// Determines the result of a `NullaryOp::UbChecks` invocation.
fn ub_checks(_ecx: &InterpCx<'tcx, Self>) -> InterpResult<'tcx, bool>;

/// Called when the interpreter encounters a `StatementKind::ConstEvalCounter` instruction.
/// You can use this to detect long or endlessly running programs.
#[inline]
Expand Down Expand Up @@ -614,6 +619,16 @@ pub macro compile_time_machine(<$tcx: lifetime>) {
unreachable!("unwinding cannot happen during compile-time evaluation")
}

#[inline(always)]
fn check_fn_target_features(
_ecx: &InterpCx<$tcx, Self>,
_instance: ty::Instance<$tcx>,
) -> InterpResult<$tcx> {
// For now we don't do any checking here. We can't use `tcx.sess` because that can differ
// between crates, and we need to ensure that const-eval always behaves the same.
Ok(())
}

#[inline(always)]
fn call_extra_fn(
_ecx: &mut InterpCx<$tcx, Self>,
Expand All @@ -627,6 +642,13 @@ pub macro compile_time_machine(<$tcx: lifetime>) {
match fn_val {}
}

#[inline(always)]
fn ub_checks(_ecx: &InterpCx<$tcx, Self>) -> InterpResult<$tcx, bool> {
// We can't look at `tcx.sess` here as that can differ across crates, which can lead to
// unsound differences in evaluating the same constant at different instantiation sites.
Ok(true)
}

#[inline(always)]
fn adjust_global_allocation<'b>(
_ecx: &InterpCx<$tcx, Self>,
Expand Down
Loading

0 comments on commit ad7a1aa

Please sign in to comment.