Merge from rustc
This commit is contained in:
commit
a01f37c7f4
@ -1743,15 +1743,23 @@ pub enum PointerKind {
|
||||
Box { unpin: bool, global: bool },
|
||||
}
|
||||
|
||||
/// Note that this information is advisory only, and backends are free to ignore it.
|
||||
/// It can only be used to encode potential optimizations, but no critical information.
|
||||
/// Encodes extra information we have about a pointer.
|
||||
/// Note that this information is advisory only, and backends are free to ignore it:
|
||||
/// if the information is wrong, that can cause UB, but if the information is absent,
|
||||
/// that must always be okay.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct PointeeInfo {
|
||||
pub size: Size,
|
||||
pub align: Align,
|
||||
/// If this is `None`, then this is a raw pointer, so size and alignment are not guaranteed to
|
||||
/// be reliable.
|
||||
pub safe: Option<PointerKind>,
|
||||
/// If `safe` is `Some`, then the pointer is either null or dereferenceable for this many bytes.
|
||||
/// On a function argument, "dereferenceable" here means "dereferenceable for the entire duration
|
||||
/// of this function call", i.e. it is UB for the memory that this pointer points to to be freed
|
||||
/// while this function is still running.
|
||||
/// The size can be zero if the pointer is not dereferenceable.
|
||||
pub size: Size,
|
||||
/// If `safe` is `Some`, then the pointer is aligned as indicated.
|
||||
pub align: Align,
|
||||
}
|
||||
|
||||
impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
|
||||
|
@ -48,6 +48,7 @@ pub(crate) fn lower_inline_asm(
|
||||
| asm::InlineAsmArch::RiscV32
|
||||
| asm::InlineAsmArch::RiscV64
|
||||
| asm::InlineAsmArch::LoongArch64
|
||||
| asm::InlineAsmArch::S390x
|
||||
);
|
||||
if !is_stable && !self.tcx.features().asm_experimental_arch() {
|
||||
feature_err(
|
||||
|
@ -1,10 +1,7 @@
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir::OpaqueTyOrigin;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, TyCtxtInferExt as _};
|
||||
use rustc_infer::traits::{Obligation, ObligationCause};
|
||||
use rustc_macros::extension;
|
||||
use rustc_middle::ty::visit::TypeVisitableExt;
|
||||
use rustc_middle::ty::{
|
||||
@ -12,7 +9,6 @@
|
||||
TypingMode,
|
||||
};
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
|
||||
use rustc_trait_selection::traits::ObligationCtxt;
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
@ -303,91 +299,7 @@ fn infer_opaque_definition_from_instantiation(
|
||||
return Ty::new_error(self.tcx, e);
|
||||
}
|
||||
|
||||
// `definition_ty` does not live in of the current inference context,
|
||||
// so lets make sure that we don't accidentally misuse our current `infcx`.
|
||||
match check_opaque_type_well_formed(
|
||||
self.tcx,
|
||||
self.next_trait_solver(),
|
||||
opaque_type_key.def_id,
|
||||
instantiated_ty.span,
|
||||
definition_ty,
|
||||
) {
|
||||
Ok(hidden_ty) => hidden_ty,
|
||||
Err(guar) => Ty::new_error(self.tcx, guar),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This logic duplicates most of `check_opaque_meets_bounds`.
|
||||
/// FIXME(oli-obk): Also do region checks here and then consider removing
|
||||
/// `check_opaque_meets_bounds` entirely.
|
||||
fn check_opaque_type_well_formed<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
next_trait_solver: bool,
|
||||
def_id: LocalDefId,
|
||||
definition_span: Span,
|
||||
definition_ty: Ty<'tcx>,
|
||||
) -> Result<Ty<'tcx>, ErrorGuaranteed> {
|
||||
// Only check this for TAIT. RPIT already supports `tests/ui/impl-trait/nested-return-type2.rs`
|
||||
// on stable and we'd break that.
|
||||
let opaque_ty_hir = tcx.hir().expect_opaque_ty(def_id);
|
||||
let OpaqueTyOrigin::TyAlias { .. } = opaque_ty_hir.origin else {
|
||||
return Ok(definition_ty);
|
||||
};
|
||||
let param_env = tcx.param_env(def_id);
|
||||
|
||||
let mut parent_def_id = def_id;
|
||||
while tcx.def_kind(parent_def_id) == DefKind::OpaqueTy {
|
||||
parent_def_id = tcx.local_parent(parent_def_id);
|
||||
}
|
||||
|
||||
// FIXME(#132279): This should eventually use the already defined hidden types
|
||||
// instead. Alternatively we'll entirely remove this function given we also check
|
||||
// the opaque in `check_opaque_meets_bounds` later.
|
||||
let infcx = tcx
|
||||
.infer_ctxt()
|
||||
.with_next_trait_solver(next_trait_solver)
|
||||
.build(TypingMode::analysis_in_body(tcx, parent_def_id));
|
||||
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
|
||||
let identity_args = GenericArgs::identity_for_item(tcx, def_id);
|
||||
|
||||
// Require that the hidden type actually fulfills all the bounds of the opaque type, even without
|
||||
// the bounds that the function supplies.
|
||||
let opaque_ty = Ty::new_opaque(tcx, def_id.to_def_id(), identity_args);
|
||||
ocx.eq(&ObligationCause::misc(definition_span, def_id), param_env, opaque_ty, definition_ty)
|
||||
.map_err(|err| {
|
||||
infcx
|
||||
.err_ctxt()
|
||||
.report_mismatched_types(
|
||||
&ObligationCause::misc(definition_span, def_id),
|
||||
param_env,
|
||||
opaque_ty,
|
||||
definition_ty,
|
||||
err,
|
||||
)
|
||||
.emit()
|
||||
})?;
|
||||
|
||||
// Require the hidden type to be well-formed with only the generics of the opaque type.
|
||||
// Defining use functions may have more bounds than the opaque type, which is ok, as long as the
|
||||
// hidden type is well formed even without those bounds.
|
||||
let predicate = ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(
|
||||
definition_ty.into(),
|
||||
)));
|
||||
ocx.register_obligation(Obligation::misc(tcx, definition_span, def_id, param_env, predicate));
|
||||
|
||||
// Check that all obligations are satisfied by the implementation's
|
||||
// version.
|
||||
let errors = ocx.select_all_or_error();
|
||||
|
||||
// This is fishy, but we check it again in `check_opaque_meets_bounds`.
|
||||
// Remove once we can prepopulate with known hidden types.
|
||||
let _ = infcx.take_opaque_types();
|
||||
|
||||
if errors.is_empty() {
|
||||
Ok(definition_ty)
|
||||
} else {
|
||||
Err(infcx.err_ctxt().report_fulfillment_errors(errors))
|
||||
definition_ty
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ index 42a26ae..5ac1042 100644
|
||||
@@ -1,3 +1,4 @@
|
||||
+#![cfg(test)]
|
||||
// tidy-alphabetical-start
|
||||
#![cfg_attr(bootstrap, feature(const_three_way_compare))]
|
||||
#![cfg_attr(bootstrap, feature(strict_provenance))]
|
||||
#![cfg_attr(not(bootstrap), feature(strict_provenance_lints))]
|
||||
--
|
||||
2.21.0 (Apple Git-122)
|
||||
|
@ -15,7 +15,7 @@ index 1e336bf..35e6f54 100644
|
||||
--- a/lib.rs
|
||||
+++ b/lib.rs
|
||||
@@ -2,7 +2,6 @@
|
||||
// tidy-alphabetical-start
|
||||
#![cfg_attr(bootstrap, feature(const_three_way_compare))]
|
||||
#![cfg_attr(bootstrap, feature(strict_provenance))]
|
||||
#![cfg_attr(not(bootstrap), feature(strict_provenance_lints))]
|
||||
-#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
|
||||
|
@ -1,4 +1,4 @@
|
||||
[toolchain]
|
||||
channel = "nightly-2024-11-02"
|
||||
channel = "nightly-2024-11-09"
|
||||
components = ["rust-src", "rustc-dev", "llvm-tools"]
|
||||
profile = "minimal"
|
||||
|
@ -11,5 +11,22 @@ rm -r compiler/rustc_codegen_cranelift/{Cargo.*,src}
|
||||
cp ../Cargo.* compiler/rustc_codegen_cranelift/
|
||||
cp -r ../src compiler/rustc_codegen_cranelift/src
|
||||
|
||||
# FIXME(rust-lang/rust#132719) remove once it doesn't break without this patch
|
||||
cat <<EOF | git apply -
|
||||
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
|
||||
index 3394f2a84a0..cb980dd4d7c 100644
|
||||
--- a/src/bootstrap/src/core/build_steps/compile.rs
|
||||
+++ b/src/bootstrap/src/core/build_steps/compile.rs
|
||||
@@ -1976,7 +1976,7 @@ fn run(self, builder: &Builder<'_>) -> Compiler {
|
||||
}
|
||||
}
|
||||
|
||||
- {
|
||||
+ if builder.config.llvm_enabled(target_compiler.host) && builder.config.llvm_tools_enabled {
|
||||
// \`llvm-strip\` is used by rustc, which is actually just a symlink to \`llvm-objcopy\`,
|
||||
// so copy and rename \`llvm-objcopy\`.
|
||||
let src_exe = exe("llvm-objcopy", target_compiler.host);
|
||||
EOF
|
||||
|
||||
./x.py build --stage 1 library/std
|
||||
popd
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
use rustc_target::abi::call::PassMode;
|
||||
use rustc_target::callconv::PassMode;
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
use cranelift_codegen::ir::{ArgumentPurpose, SigRef};
|
||||
use cranelift_codegen::isa::CallConv;
|
||||
use cranelift_module::ModuleError;
|
||||
use rustc_abi::ExternAbi;
|
||||
use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization;
|
||||
use rustc_codegen_ssa::errors::CompilerBuiltinsCannotCall;
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
@ -18,8 +19,7 @@
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_target::abi::call::{Conv, FnAbi, PassMode};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use rustc_target::callconv::{Conv, FnAbi, PassMode};
|
||||
|
||||
use self::pass_mode::*;
|
||||
pub(crate) use self::returning::codegen_return;
|
||||
@ -443,7 +443,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
|
||||
RevealAllLayoutCx(fx.tcx).fn_abi_of_fn_ptr(fn_sig, extra_args)
|
||||
};
|
||||
|
||||
let is_cold = if fn_sig.abi() == Abi::RustCold {
|
||||
let is_cold = if fn_sig.abi() == ExternAbi::RustCold {
|
||||
true
|
||||
} else {
|
||||
instance.is_some_and(|inst| {
|
||||
@ -458,7 +458,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
|
||||
}
|
||||
|
||||
// Unpack arguments tuple for closures
|
||||
let mut args = if fn_sig.abi() == Abi::RustCall {
|
||||
let mut args = if fn_sig.abi() == ExternAbi::RustCall {
|
||||
let (self_arg, pack_arg) = match args {
|
||||
[pack_arg] => (None, codegen_call_argument_operand(fx, &pack_arg.node)),
|
||||
[self_arg, pack_arg] => (
|
||||
|
@ -1,8 +1,9 @@
|
||||
//! Argument passing
|
||||
|
||||
use cranelift_codegen::ir::{ArgumentExtension, ArgumentPurpose};
|
||||
use rustc_target::abi::call::{
|
||||
ArgAbi, ArgAttributes, ArgExtension as RustcArgExtension, CastTarget, PassMode, Reg, RegKind,
|
||||
use rustc_abi::{Reg, RegKind};
|
||||
use rustc_target::callconv::{
|
||||
ArgAbi, ArgAttributes, ArgExtension as RustcArgExtension, CastTarget, PassMode,
|
||||
};
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
//! Return value handling
|
||||
|
||||
use rustc_target::abi::call::{ArgAbi, PassMode};
|
||||
use rustc_target::callconv::{ArgAbi, PassMode};
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
|
||||
use crate::prelude::*;
|
||||
|
@ -934,7 +934,7 @@ fn is_wide_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
let dst = codegen_operand(fx, dst);
|
||||
let pointee = dst
|
||||
.layout()
|
||||
.pointee_info_at(fx, rustc_target::abi::Size::ZERO)
|
||||
.pointee_info_at(fx, rustc_abi::Size::ZERO)
|
||||
.expect("Expected pointer");
|
||||
let dst = dst.load_scalar(fx);
|
||||
let src = codegen_operand(fx, src).load_scalar(fx);
|
||||
|
@ -1,13 +1,13 @@
|
||||
use cranelift_codegen::isa::TargetFrontendConfig;
|
||||
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
|
||||
use rustc_abi::{Float, Integer, Primitive};
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_middle::ty::TypeFoldable;
|
||||
use rustc_middle::ty::layout::{
|
||||
self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers,
|
||||
};
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_target::abi::call::FnAbi;
|
||||
use rustc_target::abi::{Float, Integer, Primitive};
|
||||
use rustc_target::callconv::FnAbi;
|
||||
use rustc_target::spec::{HasTargetSpec, Target};
|
||||
|
||||
use crate::constant::ConstantCx;
|
||||
@ -162,8 +162,8 @@ pub(crate) fn codegen_icmp_imm(
|
||||
pub(crate) fn codegen_bitcast(fx: &mut FunctionCx<'_, '_, '_>, dst_ty: Type, val: Value) -> Value {
|
||||
let mut flags = MemFlags::new();
|
||||
flags.set_endianness(match fx.tcx.data_layout.endian {
|
||||
rustc_target::abi::Endian::Big => cranelift_codegen::ir::Endianness::Big,
|
||||
rustc_target::abi::Endian::Little => cranelift_codegen::ir::Endianness::Little,
|
||||
rustc_abi::Endian::Big => cranelift_codegen::ir::Endianness::Big,
|
||||
rustc_abi::Endian::Little => cranelift_codegen::ir::Endianness::Little,
|
||||
});
|
||||
fx.bcx.ins().bitcast(dst_ty, flags, val)
|
||||
}
|
||||
@ -333,8 +333,8 @@ fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> rustc_target::abi::HasDataLayout for FunctionCx<'_, '_, 'tcx> {
|
||||
fn data_layout(&self) -> &rustc_target::abi::TargetDataLayout {
|
||||
impl<'tcx> rustc_abi::HasDataLayout for FunctionCx<'_, '_, 'tcx> {
|
||||
fn data_layout(&self) -> &rustc_abi::TargetDataLayout {
|
||||
&self.tcx.data_layout
|
||||
}
|
||||
}
|
||||
@ -491,8 +491,8 @@ fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> rustc_target::abi::HasDataLayout for RevealAllLayoutCx<'tcx> {
|
||||
fn data_layout(&self) -> &rustc_target::abi::TargetDataLayout {
|
||||
impl<'tcx> rustc_abi::HasDataLayout for RevealAllLayoutCx<'tcx> {
|
||||
fn data_layout(&self) -> &rustc_abi::TargetDataLayout {
|
||||
&self.0.data_layout
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@
|
||||
use rustc_hir::def_id::DefIdMap;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::{FileNameDisplayPreference, SourceFileHash, StableSourceFileId};
|
||||
use rustc_target::abi::call::FnAbi;
|
||||
use rustc_target::callconv::FnAbi;
|
||||
|
||||
pub(crate) use self::emit::{DebugReloc, DebugRelocName};
|
||||
pub(crate) use self::types::TypeDebugContext;
|
||||
|
@ -2,6 +2,7 @@
|
||||
//! standalone executable.
|
||||
|
||||
use std::fs::{self, File};
|
||||
use std::io::BufWriter;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
use std::thread::JoinHandle;
|
||||
@ -397,14 +398,19 @@ fn emit_module(
|
||||
}
|
||||
|
||||
let tmp_file = output_filenames.temp_path(OutputType::Object, Some(&name));
|
||||
let mut file = match File::create(&tmp_file) {
|
||||
let file = match File::create(&tmp_file) {
|
||||
Ok(file) => file,
|
||||
Err(err) => return Err(format!("error creating object file: {}", err)),
|
||||
};
|
||||
|
||||
let mut file = BufWriter::new(file);
|
||||
if let Err(err) = object.write_stream(&mut file) {
|
||||
return Err(format!("error writing object file: {}", err));
|
||||
}
|
||||
let file = match file.into_inner() {
|
||||
Ok(file) => file,
|
||||
Err(err) => return Err(format!("error writing object file: {}", err)),
|
||||
};
|
||||
|
||||
prof.artifact_size("object_file", &*name, file.metadata().unwrap().len());
|
||||
|
||||
|
@ -464,7 +464,7 @@ fn allocate_stack_slots(&mut self) {
|
||||
let new_slot_fn = |slot_size: &mut Size, reg_class: InlineAsmRegClass| {
|
||||
let reg_size =
|
||||
reg_class.supported_types(self.arch).iter().map(|(ty, _)| ty.size()).max().unwrap();
|
||||
let align = rustc_target::abi::Align::from_bytes(reg_size.bytes()).unwrap();
|
||||
let align = rustc_abi::Align::from_bytes(reg_size.bytes()).unwrap();
|
||||
let offset = slot_size.align_to(align);
|
||||
*slot_size = offset + reg_size;
|
||||
offset
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! Codegen SIMD intrinsics.
|
||||
|
||||
use cranelift_codegen::ir::immediates::Offset32;
|
||||
use rustc_target::abi::Endian;
|
||||
use rustc_abi::Endian;
|
||||
|
||||
use super::*;
|
||||
use crate::prelude::*;
|
||||
|
@ -241,6 +241,8 @@ fn join_codegen(
|
||||
sess: &Session,
|
||||
outputs: &OutputFilenames,
|
||||
) -> (CodegenResults, FxIndexMap<WorkProductId, WorkProduct>) {
|
||||
let _timer = sess.timer("finish_ongoing_codegen");
|
||||
|
||||
ongoing_codegen.downcast::<driver::aot::OngoingCodegen>().unwrap().join(
|
||||
sess,
|
||||
outputs,
|
||||
|
@ -2,7 +2,7 @@
|
||||
//! operations.
|
||||
|
||||
use cranelift_codegen::ir::immediates::Offset32;
|
||||
use rustc_target::abi::Align;
|
||||
use rustc_abi::Align;
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
|
@ -64,7 +64,7 @@
|
||||
use cranelift_codegen::write::{FuncWriter, PlainWriter};
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_session::config::{OutputFilenames, OutputType};
|
||||
use rustc_target::abi::call::FnAbi;
|
||||
use rustc_target::callconv::FnAbi;
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
|
@ -1,11 +1,15 @@
|
||||
use std::collections::hash_map::Entry;
|
||||
|
||||
use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext};
|
||||
use rustc_codegen_ssa::traits::*;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_index::Idx;
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_middle::mir::{Body, SourceScope};
|
||||
use rustc_middle::ty::layout::FnAbiOf;
|
||||
use rustc_middle::ty::{self, Instance};
|
||||
use rustc_session::config::DebugInfo;
|
||||
use rustc_span::BytePos;
|
||||
|
||||
use super::metadata::file_metadata;
|
||||
use super::utils::DIB;
|
||||
@ -37,10 +41,20 @@ pub(crate) fn compute_mir_scopes<'ll, 'tcx>(
|
||||
None
|
||||
};
|
||||
let mut instantiated = BitSet::new_empty(mir.source_scopes.len());
|
||||
let mut discriminators = FxHashMap::default();
|
||||
// Instantiate all scopes.
|
||||
for idx in 0..mir.source_scopes.len() {
|
||||
let scope = SourceScope::new(idx);
|
||||
make_mir_scope(cx, instance, mir, &variables, debug_context, &mut instantiated, scope);
|
||||
make_mir_scope(
|
||||
cx,
|
||||
instance,
|
||||
mir,
|
||||
&variables,
|
||||
debug_context,
|
||||
&mut instantiated,
|
||||
&mut discriminators,
|
||||
scope,
|
||||
);
|
||||
}
|
||||
assert!(instantiated.count() == mir.source_scopes.len());
|
||||
}
|
||||
@ -52,6 +66,7 @@ fn make_mir_scope<'ll, 'tcx>(
|
||||
variables: &Option<BitSet<SourceScope>>,
|
||||
debug_context: &mut FunctionDebugContext<'tcx, &'ll DIScope, &'ll DILocation>,
|
||||
instantiated: &mut BitSet<SourceScope>,
|
||||
discriminators: &mut FxHashMap<BytePos, u32>,
|
||||
scope: SourceScope,
|
||||
) {
|
||||
if instantiated.contains(scope) {
|
||||
@ -60,7 +75,16 @@ fn make_mir_scope<'ll, 'tcx>(
|
||||
|
||||
let scope_data = &mir.source_scopes[scope];
|
||||
let parent_scope = if let Some(parent) = scope_data.parent_scope {
|
||||
make_mir_scope(cx, instance, mir, variables, debug_context, instantiated, parent);
|
||||
make_mir_scope(
|
||||
cx,
|
||||
instance,
|
||||
mir,
|
||||
variables,
|
||||
debug_context,
|
||||
instantiated,
|
||||
discriminators,
|
||||
parent,
|
||||
);
|
||||
debug_context.scopes[parent]
|
||||
} else {
|
||||
// The root is the function itself.
|
||||
@ -117,7 +141,37 @@ fn make_mir_scope<'ll, 'tcx>(
|
||||
// FIXME(eddyb) this doesn't account for the macro-related
|
||||
// `Span` fixups that `rustc_codegen_ssa::mir::debuginfo` does.
|
||||
let callsite_scope = parent_scope.adjust_dbg_scope_for_span(cx, callsite_span);
|
||||
cx.dbg_loc(callsite_scope, parent_scope.inlined_at, callsite_span)
|
||||
let loc = cx.dbg_loc(callsite_scope, parent_scope.inlined_at, callsite_span);
|
||||
|
||||
// NB: In order to produce proper debug info for variables (particularly
|
||||
// arguments) in multiply-inline functions, LLVM expects to see a single
|
||||
// DILocalVariable with multiple different DILocations in the IR. While
|
||||
// the source information for each DILocation would be identical, their
|
||||
// inlinedAt attributes will be unique to the particular callsite.
|
||||
//
|
||||
// We generate DILocations here based on the callsite's location in the
|
||||
// source code. A single location in the source code usually can't
|
||||
// produce multiple distinct calls so this mostly works, until
|
||||
// proc-macros get involved. A proc-macro can generate multiple calls
|
||||
// at the same span, which breaks the assumption that we're going to
|
||||
// produce a unique DILocation for every scope we process here. We
|
||||
// have to explicitly add discriminators if we see inlines into the
|
||||
// same source code location.
|
||||
//
|
||||
// Note further that we can't key this hashtable on the span itself,
|
||||
// because these spans could have distinct SyntaxContexts. We have
|
||||
// to key on exactly what we're giving to LLVM.
|
||||
match discriminators.entry(callsite_span.lo()) {
|
||||
Entry::Occupied(mut o) => {
|
||||
*o.get_mut() += 1;
|
||||
unsafe { llvm::LLVMRustDILocationCloneWithBaseDiscriminator(loc, *o.get()) }
|
||||
.expect("Failed to encode discriminator in DILocation")
|
||||
}
|
||||
Entry::Vacant(v) => {
|
||||
v.insert(0);
|
||||
loc
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
debug_context.scopes[scope] = DebugScope {
|
||||
|
@ -204,7 +204,7 @@ pub enum DLLStorageClass {
|
||||
DllExport = 2, // Function to be accessible from DLL.
|
||||
}
|
||||
|
||||
/// Matches LLVMRustAttribute in LLVMWrapper.h
|
||||
/// Must match the layout of `LLVMRustAttributeKind`.
|
||||
/// Semantically a subset of the C++ enum llvm::Attribute::AttrKind,
|
||||
/// though it is not ABI compatible (since it's a C++ enum)
|
||||
#[repr(C)]
|
||||
@ -1766,11 +1766,9 @@ pub fn LLVMRustBuildAtomicStore<'a>(
|
||||
pub fn LLVMRustGetLastError() -> *const c_char;
|
||||
|
||||
/// Prints the timing information collected by `-Ztime-llvm-passes`.
|
||||
#[expect(improper_ctypes)]
|
||||
pub(crate) fn LLVMRustPrintPassTimings(OutStr: &RustString);
|
||||
|
||||
/// Prints the statistics collected by `-Zprint-codegen-stats`.
|
||||
#[expect(improper_ctypes)]
|
||||
pub(crate) fn LLVMRustPrintStatistics(OutStr: &RustString);
|
||||
|
||||
/// Prepares inline assembly.
|
||||
@ -1791,7 +1789,6 @@ pub fn LLVMRustInlineAsmVerify(
|
||||
ConstraintsLen: size_t,
|
||||
) -> bool;
|
||||
|
||||
#[allow(improper_ctypes)]
|
||||
pub(crate) fn LLVMRustCoverageWriteFilenamesToBuffer(
|
||||
Filenames: *const *const c_char,
|
||||
FilenamesLen: size_t,
|
||||
@ -1800,7 +1797,6 @@ pub(crate) fn LLVMRustCoverageWriteFilenamesToBuffer(
|
||||
BufferOut: &RustString,
|
||||
);
|
||||
|
||||
#[allow(improper_ctypes)]
|
||||
pub(crate) fn LLVMRustCoverageWriteFunctionMappingsToBuffer(
|
||||
VirtualFileMappingIDs: *const c_uint,
|
||||
NumVirtualFileMappingIDs: size_t,
|
||||
@ -1824,13 +1820,10 @@ pub(crate) fn LLVMRustCoverageCreatePGOFuncNameVar(
|
||||
) -> &Value;
|
||||
pub(crate) fn LLVMRustCoverageHashBytes(Bytes: *const c_char, NumBytes: size_t) -> u64;
|
||||
|
||||
#[allow(improper_ctypes)]
|
||||
pub(crate) fn LLVMRustCoverageWriteCovmapSectionNameToString(M: &Module, OutStr: &RustString);
|
||||
|
||||
#[allow(improper_ctypes)]
|
||||
pub(crate) fn LLVMRustCoverageWriteCovfunSectionNameToString(M: &Module, OutStr: &RustString);
|
||||
|
||||
#[allow(improper_ctypes)]
|
||||
pub(crate) fn LLVMRustCoverageWriteCovmapVarNameToString(OutStr: &RustString);
|
||||
|
||||
pub(crate) fn LLVMRustCoverageMappingVersion() -> u32;
|
||||
@ -2181,18 +2174,19 @@ pub fn LLVMRustDIBuilderCreateDebugLocation<'a>(
|
||||
Scope: &'a DIScope,
|
||||
InlinedAt: Option<&'a DILocation>,
|
||||
) -> &'a DILocation;
|
||||
pub fn LLVMRustDILocationCloneWithBaseDiscriminator<'a>(
|
||||
Location: &'a DILocation,
|
||||
BD: c_uint,
|
||||
) -> Option<&'a DILocation>;
|
||||
pub fn LLVMRustDIBuilderCreateOpDeref() -> u64;
|
||||
pub fn LLVMRustDIBuilderCreateOpPlusUconst() -> u64;
|
||||
pub fn LLVMRustDIBuilderCreateOpLLVMFragment() -> u64;
|
||||
|
||||
#[allow(improper_ctypes)]
|
||||
pub fn LLVMRustWriteTypeToString(Type: &Type, s: &RustString);
|
||||
#[allow(improper_ctypes)]
|
||||
pub fn LLVMRustWriteValueToString(value_ref: &Value, s: &RustString);
|
||||
|
||||
pub fn LLVMRustHasFeature(T: &TargetMachine, s: *const c_char) -> bool;
|
||||
|
||||
#[allow(improper_ctypes)]
|
||||
pub(crate) fn LLVMRustPrintTargetCPUs(TM: &TargetMachine, OutStr: &RustString);
|
||||
pub fn LLVMRustGetTargetFeaturesCount(T: &TargetMachine) -> size_t;
|
||||
pub fn LLVMRustGetTargetFeature(
|
||||
@ -2297,10 +2291,8 @@ pub fn LLVMRustArchiveIteratorNext<'a>(
|
||||
pub fn LLVMRustArchiveIteratorFree<'a>(AIR: &'a mut ArchiveIterator<'a>);
|
||||
pub fn LLVMRustDestroyArchive(AR: &'static mut Archive);
|
||||
|
||||
#[allow(improper_ctypes)]
|
||||
pub fn LLVMRustWriteTwineToString(T: &Twine, s: &RustString);
|
||||
|
||||
#[allow(improper_ctypes)]
|
||||
pub fn LLVMRustUnpackOptimizationDiagnostic<'a>(
|
||||
DI: &'a DiagnosticInfo,
|
||||
pass_name_out: &RustString,
|
||||
@ -2318,7 +2310,6 @@ pub fn LLVMRustUnpackInlineAsmDiagnostic<'a>(
|
||||
message_out: &mut Option<&'a Twine>,
|
||||
);
|
||||
|
||||
#[allow(improper_ctypes)]
|
||||
pub fn LLVMRustWriteDiagnosticInfoToString(DI: &DiagnosticInfo, s: &RustString);
|
||||
pub fn LLVMRustGetDiagInfoKind(DI: &DiagnosticInfo) -> DiagnosticKind;
|
||||
|
||||
@ -2327,7 +2318,6 @@ pub fn LLVMRustGetSMDiagnostic<'a>(
|
||||
cookie_out: &mut c_uint,
|
||||
) -> &'a SMDiagnostic;
|
||||
|
||||
#[allow(improper_ctypes)]
|
||||
pub fn LLVMRustUnpackSMDiagnostic(
|
||||
d: &SMDiagnostic,
|
||||
message_out: &RustString,
|
||||
@ -2374,7 +2364,6 @@ pub fn LLVMRustWriteImportLibrary(
|
||||
pub fn LLVMRustModuleBufferLen(p: &ModuleBuffer) -> usize;
|
||||
pub fn LLVMRustModuleBufferFree(p: &'static mut ModuleBuffer);
|
||||
pub fn LLVMRustModuleCost(M: &Module) -> u64;
|
||||
#[allow(improper_ctypes)]
|
||||
pub fn LLVMRustModuleInstructionStats(M: &Module, Str: &RustString);
|
||||
|
||||
pub fn LLVMRustThinLTOBufferCreate(
|
||||
@ -2427,7 +2416,6 @@ pub fn LLVMRustLinkerAdd(
|
||||
bytecode_len: usize,
|
||||
) -> bool;
|
||||
pub fn LLVMRustLinkerFree<'a>(linker: &'a mut Linker<'a>);
|
||||
#[allow(improper_ctypes)]
|
||||
pub fn LLVMRustComputeLTOCacheKey(
|
||||
key_out: &RustString,
|
||||
mod_id: *const c_char,
|
||||
@ -2450,7 +2438,6 @@ pub fn LLVMRustContextConfigureDiagnosticHandler(
|
||||
pgo_available: bool,
|
||||
);
|
||||
|
||||
#[allow(improper_ctypes)]
|
||||
pub fn LLVMRustGetMangledName(V: &Value, out: &RustString);
|
||||
|
||||
pub fn LLVMRustGetElementTypeArgIndex(CallSite: &Value) -> i32;
|
||||
|
@ -1,6 +1,5 @@
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::ops::Deref;
|
||||
use std::ptr;
|
||||
@ -301,15 +300,11 @@ pub fn set_value_name(value: &Value, name: &[u8]) {
|
||||
}
|
||||
|
||||
pub fn build_string(f: impl FnOnce(&RustString)) -> Result<String, FromUtf8Error> {
|
||||
let sr = RustString { bytes: RefCell::new(Vec::new()) };
|
||||
f(&sr);
|
||||
String::from_utf8(sr.bytes.into_inner())
|
||||
String::from_utf8(RustString::build_byte_buffer(f))
|
||||
}
|
||||
|
||||
pub fn build_byte_buffer(f: impl FnOnce(&RustString)) -> Vec<u8> {
|
||||
let sr = RustString { bytes: RefCell::new(Vec::new()) };
|
||||
f(&sr);
|
||||
sr.bytes.into_inner()
|
||||
RustString::build_byte_buffer(f)
|
||||
}
|
||||
|
||||
pub fn twine_to_string(tr: &Twine) -> String {
|
||||
|
@ -228,6 +228,8 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
|
||||
"x86"
|
||||
} else if sess.target.arch == "arm64ec" {
|
||||
"aarch64"
|
||||
} else if sess.target.arch == "sparc64" {
|
||||
"sparc"
|
||||
} else {
|
||||
&*sess.target.arch
|
||||
};
|
||||
@ -280,6 +282,13 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
|
||||
// Support for `wide-arithmetic` will first land in LLVM 20 as part of
|
||||
// llvm/llvm-project#111598
|
||||
("wasm32" | "wasm64", "wide-arithmetic") if get_version() < (20, 0, 0) => None,
|
||||
("sparc", "leoncasa") => Some(LLVMFeature::new("hasleoncasa")),
|
||||
// In LLVM 19, there is no `v8plus` feature and `v9` means "SPARC-V9 instruction available and SPARC-V8+ ABI used".
|
||||
// https://github.com/llvm/llvm-project/blob/llvmorg-19.1.0/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp#L27-L28
|
||||
// Before LLVM 19, there is no `v8plus` feature and `v9` means "SPARC-V9 instruction available".
|
||||
// https://github.com/llvm/llvm-project/blob/llvmorg-18.1.0/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp#L26
|
||||
("sparc", "v8plus") if get_version().0 == 19 => Some(LLVMFeature::new("v9")),
|
||||
("sparc", "v8plus") if get_version().0 < 19 => None,
|
||||
(_, s) => Some(LLVMFeature::new(s)),
|
||||
}
|
||||
}
|
||||
@ -619,6 +628,8 @@ pub(crate) fn global_llvm_features(
|
||||
.features
|
||||
.split(',')
|
||||
.filter(|v| !v.is_empty() && backend_feature_name(sess, v).is_some())
|
||||
// Drop +v8plus feature introduced in LLVM 20.
|
||||
.filter(|v| *v != "+v8plus" || get_version() >= (20, 0, 0))
|
||||
.map(String::from),
|
||||
);
|
||||
|
||||
|
@ -3305,23 +3305,6 @@ fn add_lld_args(
|
||||
let self_contained_cli = sess.opts.cg.link_self_contained.is_linker_enabled();
|
||||
let self_contained_target = self_contained_components.is_linker_enabled();
|
||||
|
||||
// FIXME: in the future, codegen backends may need to have more control over this process: they
|
||||
// don't always support all the features the linker expects here, and vice versa. For example,
|
||||
// at the time of writing this, lld expects a newer style of aarch64 TLS relocations that
|
||||
// cranelift doesn't implement yet. That in turn can impact whether linking would succeed on
|
||||
// such a target when using the `cg_clif` backend and lld.
|
||||
//
|
||||
// Until interactions between backends and linker features are expressible, we limit target
|
||||
// specs to opt-in to lld only when we're on the llvm backend, where it's expected to work and
|
||||
// tested on CI. As usual, the CLI still has precedence over this, so that users and developers
|
||||
// can still override this default when needed (e.g. for tests).
|
||||
let uses_llvm_backend =
|
||||
matches!(sess.opts.unstable_opts.codegen_backend.as_deref(), None | Some("llvm"));
|
||||
if !uses_llvm_backend && !self_contained_cli && sess.opts.cg.linker_flavor.is_none() {
|
||||
// We bail if we're not using llvm and lld was not explicitly requested on the CLI.
|
||||
return;
|
||||
}
|
||||
|
||||
let self_contained_linker = self_contained_cli || self_contained_target;
|
||||
if self_contained_linker && !sess.opts.cg.link_self_contained.is_linker_disabled() {
|
||||
let mut linker_path_exists = false;
|
||||
|
@ -212,7 +212,7 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
|
||||
"riscv32" => (Architecture::Riscv32, None),
|
||||
"riscv64" => (Architecture::Riscv64, None),
|
||||
"sparc" => {
|
||||
if sess.target.options.cpu == "v9" {
|
||||
if sess.unstable_target_features.contains(&sym::v8plus) {
|
||||
// Target uses V8+, aka EM_SPARC32PLUS, aka 64-bit V9 but in 32-bit mode
|
||||
(Architecture::Sparc32Plus, None)
|
||||
} else {
|
||||
|
@ -25,6 +25,10 @@ const_eval_closure_fndef_not_const =
|
||||
function defined here, but it is not `const`
|
||||
const_eval_closure_non_const =
|
||||
cannot call non-const closure in {const_eval_const_context}s
|
||||
|
||||
const_eval_conditionally_const_call =
|
||||
cannot call conditionally-const {$def_descr} `{$def_path_str}` in {const_eval_const_context}s
|
||||
|
||||
const_eval_consider_dereferencing =
|
||||
consider dereferencing here
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::adjustment::PointerCoercion;
|
||||
use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TypeVisitableExt};
|
||||
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
|
||||
use rustc_mir_dataflow::Analysis;
|
||||
use rustc_mir_dataflow::impls::MaybeStorageLive;
|
||||
use rustc_mir_dataflow::storage::always_storage_live_locals;
|
||||
@ -361,31 +361,21 @@ fn place_may_escape(&mut self, place: &Place<'_>) -> bool {
|
||||
!is_transient
|
||||
}
|
||||
|
||||
/// Returns whether there are const-conditions.
|
||||
fn revalidate_conditional_constness(
|
||||
&mut self,
|
||||
callee: DefId,
|
||||
callee_args: ty::GenericArgsRef<'tcx>,
|
||||
call_source: CallSource,
|
||||
call_span: Span,
|
||||
) {
|
||||
) -> bool {
|
||||
let tcx = self.tcx;
|
||||
if !tcx.is_conditionally_const(callee) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
let const_conditions = tcx.const_conditions(callee).instantiate(tcx, callee_args);
|
||||
// If there are any const conditions on this fn and `const_trait_impl`
|
||||
// is not enabled, simply bail. We shouldn't be able to call conditionally
|
||||
// const functions on stable.
|
||||
if !const_conditions.is_empty() && !tcx.features().const_trait_impl() {
|
||||
self.check_op(ops::FnCallNonConst {
|
||||
callee,
|
||||
args: callee_args,
|
||||
span: call_span,
|
||||
call_source,
|
||||
feature: Some(sym::const_trait_impl),
|
||||
});
|
||||
return;
|
||||
if const_conditions.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let infcx = tcx.infer_ctxt().build(self.body.typing_mode(tcx));
|
||||
@ -421,6 +411,8 @@ fn revalidate_conditional_constness(
|
||||
tcx.dcx()
|
||||
.span_delayed_bug(call_span, "this should have reported a ~const error in HIR");
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
@ -627,11 +619,11 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let ConstCx { tcx, body, param_env, .. } = *self.ccx;
|
||||
let ConstCx { tcx, body, .. } = *self.ccx;
|
||||
|
||||
let fn_ty = func.ty(body, tcx);
|
||||
|
||||
let (mut callee, mut fn_args) = match *fn_ty.kind() {
|
||||
let (callee, fn_args) = match *fn_ty.kind() {
|
||||
ty::FnDef(def_id, fn_args) => (def_id, fn_args),
|
||||
|
||||
ty::FnPtr(..) => {
|
||||
@ -645,57 +637,38 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
|
||||
}
|
||||
};
|
||||
|
||||
self.revalidate_conditional_constness(callee, fn_args, call_source, *fn_span);
|
||||
let has_const_conditions =
|
||||
self.revalidate_conditional_constness(callee, fn_args, *fn_span);
|
||||
|
||||
let mut is_trait = false;
|
||||
// Attempting to call a trait method?
|
||||
if let Some(trait_did) = tcx.trait_of_item(callee) {
|
||||
// We can't determine the actual callee here, so we have to do different checks
|
||||
// than usual.
|
||||
|
||||
trace!("attempting to call a trait method");
|
||||
|
||||
let trait_is_const = tcx.is_const_trait(trait_did);
|
||||
// trait method calls are only permitted when `effects` is enabled.
|
||||
// typeck ensures the conditions for calling a const trait method are met,
|
||||
// so we only error if the trait isn't const. We try to resolve the trait
|
||||
// into the concrete method, and uses that for const stability checks.
|
||||
// FIXME(const_trait_impl) we might consider moving const stability checks
|
||||
// to typeck as well.
|
||||
if tcx.features().const_trait_impl() && trait_is_const {
|
||||
// This skips the check below that ensures we only call `const fn`.
|
||||
is_trait = true;
|
||||
|
||||
if let Ok(Some(instance)) =
|
||||
Instance::try_resolve(tcx, param_env, callee, fn_args)
|
||||
&& let InstanceKind::Item(def) = instance.def
|
||||
{
|
||||
// Resolve a trait method call to its concrete implementation, which may be in a
|
||||
// `const` trait impl. This is only used for the const stability check below, since
|
||||
// we want to look at the concrete impl's stability.
|
||||
fn_args = instance.args;
|
||||
callee = def;
|
||||
}
|
||||
if trait_is_const {
|
||||
// Trait calls are always conditionally-const.
|
||||
self.check_op(ops::ConditionallyConstCall { callee, args: fn_args });
|
||||
// FIXME(const_trait_impl): do a more fine-grained check whether this
|
||||
// particular trait can be const-stably called.
|
||||
} else {
|
||||
// if the trait is const but the user has not enabled the feature(s),
|
||||
// suggest them.
|
||||
let feature = if trait_is_const {
|
||||
Some(if tcx.features().const_trait_impl() {
|
||||
sym::effects
|
||||
} else {
|
||||
sym::const_trait_impl
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
// Not even a const trait.
|
||||
self.check_op(ops::FnCallNonConst {
|
||||
callee,
|
||||
args: fn_args,
|
||||
span: *fn_span,
|
||||
call_source,
|
||||
feature,
|
||||
});
|
||||
// If we allowed this, we're in miri-unleashed mode, so we might
|
||||
// as well skip the remaining checks.
|
||||
return;
|
||||
}
|
||||
// That's all we can check here.
|
||||
return;
|
||||
}
|
||||
|
||||
// Even if we know the callee, ensure we can use conditionally-const calls.
|
||||
if has_const_conditions {
|
||||
self.check_op(ops::ConditionallyConstCall { callee, args: fn_args });
|
||||
}
|
||||
|
||||
// At this point, we are calling a function, `callee`, whose `DefId` is known...
|
||||
@ -783,14 +756,12 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
|
||||
return;
|
||||
}
|
||||
|
||||
// Trait functions are not `const fn` so we have to skip them here.
|
||||
if !tcx.is_const_fn(callee) && !is_trait {
|
||||
if !tcx.is_const_fn(callee) {
|
||||
self.check_op(ops::FnCallNonConst {
|
||||
callee,
|
||||
args: fn_args,
|
||||
span: *fn_span,
|
||||
call_source,
|
||||
feature: None,
|
||||
});
|
||||
// If we allowed this, we're in miri-unleashed mode, so we might
|
||||
// as well skip the remaining checks.
|
||||
|
@ -70,6 +70,37 @@ fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// A call to a function that is in a trait, or has trait bounds that make it conditionally-const.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ConditionallyConstCall<'tcx> {
|
||||
pub callee: DefId,
|
||||
pub args: GenericArgsRef<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> NonConstOp<'tcx> for ConditionallyConstCall<'tcx> {
|
||||
fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
|
||||
// We use the `const_trait_impl` gate for all conditionally-const calls.
|
||||
Status::Unstable {
|
||||
gate: sym::const_trait_impl,
|
||||
safe_to_expose_on_stable: false,
|
||||
// We don't want the "mark the callee as `#[rustc_const_stable_indirect]`" hint
|
||||
is_function_call: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
||||
ccx.tcx.sess.create_feature_err(
|
||||
errors::ConditionallyConstCall {
|
||||
span,
|
||||
def_path_str: ccx.tcx.def_path_str_with_args(self.callee, self.args),
|
||||
def_descr: ccx.tcx.def_descr(self.callee),
|
||||
kind: ccx.const_kind(),
|
||||
},
|
||||
sym::const_trait_impl,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// A function call where the callee is not marked as `const`.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub(crate) struct FnCallNonConst<'tcx> {
|
||||
@ -77,7 +108,6 @@ pub(crate) struct FnCallNonConst<'tcx> {
|
||||
pub args: GenericArgsRef<'tcx>,
|
||||
pub span: Span,
|
||||
pub call_source: CallSource,
|
||||
pub feature: Option<Symbol>,
|
||||
}
|
||||
|
||||
impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
|
||||
@ -85,7 +115,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, _: Span) -> Diag<'tcx> {
|
||||
let FnCallNonConst { callee, args, span, call_source, feature } = *self;
|
||||
let FnCallNonConst { callee, args, span, call_source } = *self;
|
||||
let ConstCx { tcx, param_env, .. } = *ccx;
|
||||
let caller = ccx.def_id();
|
||||
|
||||
@ -285,14 +315,6 @@ macro_rules! error {
|
||||
ccx.const_kind(),
|
||||
));
|
||||
|
||||
if let Some(feature) = feature {
|
||||
ccx.tcx.disabled_nightly_features(
|
||||
&mut err,
|
||||
Some(ccx.tcx.local_def_id_to_hir_id(caller)),
|
||||
[(String::new(), feature)],
|
||||
);
|
||||
}
|
||||
|
||||
if let ConstContext::Static(_) = ccx.const_kind() {
|
||||
err.note(fluent_generated::const_eval_lazy_lock);
|
||||
}
|
||||
@ -398,15 +420,8 @@ fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
|
||||
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
||||
let msg = format!("{:#}s are not allowed in {}s", self.0, ccx.const_kind());
|
||||
if let hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::Async,
|
||||
hir::CoroutineSource::Block,
|
||||
) = self.0
|
||||
{
|
||||
ccx.tcx.sess.create_feature_err(
|
||||
errors::UnallowedOpInConstContext { span, msg },
|
||||
sym::const_async_blocks,
|
||||
)
|
||||
if let Status::Unstable { gate, .. } = self.status_in_item(ccx) {
|
||||
ccx.tcx.sess.create_feature_err(errors::UnallowedOpInConstContext { span, msg }, gate)
|
||||
} else {
|
||||
ccx.dcx().create_err(errors::UnallowedOpInConstContext { span, msg })
|
||||
}
|
||||
|
@ -472,8 +472,9 @@ fn report_validation_error<'tcx>(
|
||||
backtrace.print_backtrace();
|
||||
|
||||
let bytes = ecx.print_alloc_bytes_for_diagnostics(alloc_id);
|
||||
let (size, align, _) = ecx.get_alloc_info(alloc_id);
|
||||
let raw_bytes = errors::RawBytesNote { size: size.bytes(), align: align.bytes(), bytes };
|
||||
let info = ecx.get_alloc_info(alloc_id);
|
||||
let raw_bytes =
|
||||
errors::RawBytesNote { size: info.size.bytes(), align: info.align.bytes(), bytes };
|
||||
|
||||
crate::const_eval::report(
|
||||
*ecx.tcx,
|
||||
|
@ -176,6 +176,16 @@ pub(crate) struct NonConstFmtMacroCall {
|
||||
pub kind: ConstContext,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(const_eval_conditionally_const_call)]
|
||||
pub(crate) struct ConditionallyConstCall {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub def_path_str: String,
|
||||
pub def_descr: &'static str,
|
||||
pub kind: ConstContext,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(const_eval_non_const_fn_call, code = E0015)]
|
||||
pub(crate) struct NonConstFnCall {
|
||||
|
@ -14,10 +14,9 @@
|
||||
use rustc_abi::{Align, HasDataLayout, Size};
|
||||
use rustc_ast::Mutability;
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::mir::display_allocation;
|
||||
use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
|
||||
use tracing::{debug, instrument, trace};
|
||||
|
||||
use super::{
|
||||
@ -72,6 +71,21 @@ pub enum AllocKind {
|
||||
Dead,
|
||||
}
|
||||
|
||||
/// Metadata about an `AllocId`.
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub struct AllocInfo {
|
||||
pub size: Size,
|
||||
pub align: Align,
|
||||
pub kind: AllocKind,
|
||||
pub mutbl: Mutability,
|
||||
}
|
||||
|
||||
impl AllocInfo {
|
||||
fn new(size: Size, align: Align, kind: AllocKind, mutbl: Mutability) -> Self {
|
||||
Self { size, align, kind, mutbl }
|
||||
}
|
||||
}
|
||||
|
||||
/// The value of a function pointer.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum FnVal<'tcx, Other> {
|
||||
@ -524,17 +538,22 @@ fn is_offset_misaligned(offset: u64, align: Align) -> Option<Misalignment> {
|
||||
match self.ptr_try_get_alloc_id(ptr, 0) {
|
||||
Err(addr) => is_offset_misaligned(addr, align),
|
||||
Ok((alloc_id, offset, _prov)) => {
|
||||
let (_size, alloc_align, kind) = self.get_alloc_info(alloc_id);
|
||||
if let Some(misalign) =
|
||||
M::alignment_check(self, alloc_id, alloc_align, kind, offset, align)
|
||||
{
|
||||
let alloc_info = self.get_alloc_info(alloc_id);
|
||||
if let Some(misalign) = M::alignment_check(
|
||||
self,
|
||||
alloc_id,
|
||||
alloc_info.align,
|
||||
alloc_info.kind,
|
||||
offset,
|
||||
align,
|
||||
) {
|
||||
Some(misalign)
|
||||
} else if M::Provenance::OFFSET_IS_ADDR {
|
||||
is_offset_misaligned(ptr.addr().bytes(), align)
|
||||
} else {
|
||||
// Check allocation alignment and offset alignment.
|
||||
if alloc_align.bytes() < align.bytes() {
|
||||
Some(Misalignment { has: alloc_align, required: align })
|
||||
if alloc_info.align.bytes() < align.bytes() {
|
||||
Some(Misalignment { has: alloc_info.align, required: align })
|
||||
} else {
|
||||
is_offset_misaligned(offset.bytes(), align)
|
||||
}
|
||||
@ -818,82 +837,45 @@ pub fn is_alloc_live(&self, id: AllocId) -> bool {
|
||||
|
||||
/// Obtain the size and alignment of an allocation, even if that allocation has
|
||||
/// been deallocated.
|
||||
pub fn get_alloc_info(&self, id: AllocId) -> (Size, Align, AllocKind) {
|
||||
pub fn get_alloc_info(&self, id: AllocId) -> AllocInfo {
|
||||
// # Regular allocations
|
||||
// Don't use `self.get_raw` here as that will
|
||||
// a) cause cycles in case `id` refers to a static
|
||||
// b) duplicate a global's allocation in miri
|
||||
if let Some((_, alloc)) = self.memory.alloc_map.get(id) {
|
||||
return (alloc.size(), alloc.align, AllocKind::LiveData);
|
||||
return AllocInfo::new(
|
||||
alloc.size(),
|
||||
alloc.align,
|
||||
AllocKind::LiveData,
|
||||
alloc.mutability,
|
||||
);
|
||||
}
|
||||
|
||||
// # Function pointers
|
||||
// (both global from `alloc_map` and local from `extra_fn_ptr_map`)
|
||||
if self.get_fn_alloc(id).is_some() {
|
||||
return (Size::ZERO, Align::ONE, AllocKind::Function);
|
||||
return AllocInfo::new(Size::ZERO, Align::ONE, AllocKind::Function, Mutability::Not);
|
||||
}
|
||||
|
||||
// # Statics
|
||||
// Can't do this in the match argument, we may get cycle errors since the lock would
|
||||
// be held throughout the match.
|
||||
match self.tcx.try_get_global_alloc(id) {
|
||||
Some(GlobalAlloc::Static(def_id)) => {
|
||||
// Thread-local statics do not have a constant address. They *must* be accessed via
|
||||
// `ThreadLocalRef`; we can never have a pointer to them as a regular constant value.
|
||||
assert!(!self.tcx.is_thread_local_static(def_id));
|
||||
|
||||
let DefKind::Static { nested, .. } = self.tcx.def_kind(def_id) else {
|
||||
bug!("GlobalAlloc::Static is not a static")
|
||||
};
|
||||
|
||||
let (size, align) = if nested {
|
||||
// Nested anonymous statics are untyped, so let's get their
|
||||
// size and alignment from the allocation itself. This always
|
||||
// succeeds, as the query is fed at DefId creation time, so no
|
||||
// evaluation actually occurs.
|
||||
let alloc = self.tcx.eval_static_initializer(def_id).unwrap();
|
||||
(alloc.0.size(), alloc.0.align)
|
||||
} else {
|
||||
// Use size and align of the type for everything else. We need
|
||||
// to do that to
|
||||
// * avoid cycle errors in case of self-referential statics,
|
||||
// * be able to get information on extern statics.
|
||||
let ty = self
|
||||
.tcx
|
||||
.type_of(def_id)
|
||||
.no_bound_vars()
|
||||
.expect("statics should not have generic parameters");
|
||||
let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap();
|
||||
assert!(layout.is_sized());
|
||||
(layout.size, layout.align.abi)
|
||||
};
|
||||
(size, align, AllocKind::LiveData)
|
||||
}
|
||||
Some(GlobalAlloc::Memory(alloc)) => {
|
||||
// Need to duplicate the logic here, because the global allocations have
|
||||
// different associated types than the interpreter-local ones.
|
||||
let alloc = alloc.inner();
|
||||
(alloc.size(), alloc.align, AllocKind::LiveData)
|
||||
}
|
||||
Some(GlobalAlloc::Function { .. }) => {
|
||||
bug!("We already checked function pointers above")
|
||||
}
|
||||
Some(GlobalAlloc::VTable(..)) => {
|
||||
// No data to be accessed here. But vtables are pointer-aligned.
|
||||
return (Size::ZERO, self.tcx.data_layout.pointer_align.abi, AllocKind::VTable);
|
||||
}
|
||||
// The rest must be dead.
|
||||
None => {
|
||||
// Deallocated pointers are allowed, we should be able to find
|
||||
// them in the map.
|
||||
let (size, align) = *self
|
||||
.memory
|
||||
.dead_alloc_map
|
||||
.get(&id)
|
||||
.expect("deallocated pointers should all be recorded in `dead_alloc_map`");
|
||||
(size, align, AllocKind::Dead)
|
||||
}
|
||||
// # Global allocations
|
||||
if let Some(global_alloc) = self.tcx.try_get_global_alloc(id) {
|
||||
let (size, align) = global_alloc.size_and_align(*self.tcx, self.param_env);
|
||||
let mutbl = global_alloc.mutability(*self.tcx, self.param_env);
|
||||
let kind = match global_alloc {
|
||||
GlobalAlloc::Static { .. } | GlobalAlloc::Memory { .. } => AllocKind::LiveData,
|
||||
GlobalAlloc::Function { .. } => bug!("We already checked function pointers above"),
|
||||
GlobalAlloc::VTable { .. } => AllocKind::VTable,
|
||||
};
|
||||
return AllocInfo::new(size, align, kind, mutbl);
|
||||
}
|
||||
|
||||
// # Dead pointers
|
||||
let (size, align) = *self
|
||||
.memory
|
||||
.dead_alloc_map
|
||||
.get(&id)
|
||||
.expect("deallocated pointers should all be recorded in `dead_alloc_map`");
|
||||
AllocInfo::new(size, align, AllocKind::Dead, Mutability::Not)
|
||||
}
|
||||
|
||||
/// Obtain the size and alignment of a *live* allocation.
|
||||
@ -902,11 +884,11 @@ fn get_live_alloc_size_and_align(
|
||||
id: AllocId,
|
||||
msg: CheckInAllocMsg,
|
||||
) -> InterpResult<'tcx, (Size, Align)> {
|
||||
let (size, align, kind) = self.get_alloc_info(id);
|
||||
if matches!(kind, AllocKind::Dead) {
|
||||
let info = self.get_alloc_info(id);
|
||||
if matches!(info.kind, AllocKind::Dead) {
|
||||
throw_ub!(PointerUseAfterFree(id, msg))
|
||||
}
|
||||
interp_ok((size, align))
|
||||
interp_ok((info.size, info.align))
|
||||
}
|
||||
|
||||
fn get_fn_alloc(&self, id: AllocId) -> Option<FnVal<'tcx, M::ExtraFnVal>> {
|
||||
@ -1458,7 +1440,7 @@ pub fn scalar_may_be_null(&self, scalar: Scalar<M::Provenance>) -> InterpResult<
|
||||
let ptr = scalar.to_pointer(self)?;
|
||||
match self.ptr_try_get_alloc_id(ptr, 0) {
|
||||
Ok((alloc_id, offset, _)) => {
|
||||
let (size, _align, _kind) = self.get_alloc_info(alloc_id);
|
||||
let size = self.get_alloc_info(alloc_id).size;
|
||||
// If the pointer is out-of-bounds, it may be null.
|
||||
// Note that one-past-the-end (offset == size) is still inbounds, and never null.
|
||||
offset > size
|
||||
|
@ -31,7 +31,7 @@
|
||||
};
|
||||
pub(crate) use self::intrinsics::eval_nullary_intrinsic;
|
||||
pub use self::machine::{AllocMap, Machine, MayLeak, ReturnAction, compile_time_machine};
|
||||
pub use self::memory::{AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind};
|
||||
pub use self::memory::{AllocInfo, AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind};
|
||||
use self::operand::Operand;
|
||||
pub use self::operand::{ImmTy, Immediate, OpTy};
|
||||
pub use self::place::{MPlaceTy, MemPlaceMeta, PlaceTy, Writeable};
|
||||
|
@ -31,8 +31,8 @@
|
||||
|
||||
use super::machine::AllocMap;
|
||||
use super::{
|
||||
AllocId, AllocKind, CheckInAllocMsg, GlobalAlloc, ImmTy, Immediate, InterpCx, InterpResult,
|
||||
MPlaceTy, Machine, MemPlaceMeta, PlaceTy, Pointer, Projectable, Scalar, ValueVisitor, err_ub,
|
||||
AllocId, CheckInAllocMsg, GlobalAlloc, ImmTy, Immediate, InterpCx, InterpResult, MPlaceTy,
|
||||
Machine, MemPlaceMeta, PlaceTy, Pointer, Projectable, Scalar, ValueVisitor, err_ub,
|
||||
format_interp_error,
|
||||
};
|
||||
|
||||
@ -557,9 +557,20 @@ fn check_safe_pointer(
|
||||
if let Ok((alloc_id, _offset, _prov)) =
|
||||
self.ecx.ptr_try_get_alloc_id(place.ptr(), 0)
|
||||
{
|
||||
if let Some(GlobalAlloc::Static(did)) =
|
||||
self.ecx.tcx.try_get_global_alloc(alloc_id)
|
||||
{
|
||||
// Everything should be already interned.
|
||||
let Some(global_alloc) = self.ecx.tcx.try_get_global_alloc(alloc_id) else {
|
||||
assert!(self.ecx.memory.alloc_map.get(alloc_id).is_none());
|
||||
// We can't have *any* references to non-existing allocations in const-eval
|
||||
// as the rest of rustc isn't happy with them... so we throw an error, even
|
||||
// though for zero-sized references this isn't really UB.
|
||||
// A potential future alternative would be to resurrect this as a zero-sized allocation
|
||||
// (which codegen will then compile to an aligned dummy pointer anyway).
|
||||
throw_validation_failure!(self.path, DanglingPtrUseAfterFree { ptr_kind });
|
||||
};
|
||||
let (size, _align) =
|
||||
global_alloc.size_and_align(*self.ecx.tcx, self.ecx.param_env);
|
||||
|
||||
if let GlobalAlloc::Static(did) = global_alloc {
|
||||
let DefKind::Static { nested, .. } = self.ecx.tcx.def_kind(did) else {
|
||||
bug!()
|
||||
};
|
||||
@ -593,17 +604,6 @@ fn check_safe_pointer(
|
||||
}
|
||||
}
|
||||
|
||||
// Dangling and Mutability check.
|
||||
let (size, _align, alloc_kind) = self.ecx.get_alloc_info(alloc_id);
|
||||
if alloc_kind == AllocKind::Dead {
|
||||
// This can happen for zero-sized references. We can't have *any* references to
|
||||
// non-existing allocations in const-eval though, interning rejects them all as
|
||||
// the rest of rustc isn't happy with them... so we throw an error, even though
|
||||
// this isn't really UB.
|
||||
// A potential future alternative would be to resurrect this as a zero-sized allocation
|
||||
// (which codegen will then compile to an aligned dummy pointer anyway).
|
||||
throw_validation_failure!(self.path, DanglingPtrUseAfterFree { ptr_kind });
|
||||
}
|
||||
// If this allocation has size zero, there is no actual mutability here.
|
||||
if size != Size::ZERO {
|
||||
// Determine whether this pointer expects to be pointing to something mutable.
|
||||
@ -618,7 +618,8 @@ fn check_safe_pointer(
|
||||
}
|
||||
};
|
||||
// Determine what it actually points to.
|
||||
let alloc_actual_mutbl = mutability(self.ecx, alloc_id);
|
||||
let alloc_actual_mutbl =
|
||||
global_alloc.mutability(*self.ecx.tcx, self.ecx.param_env);
|
||||
// Mutable pointer to immutable memory is no good.
|
||||
if ptr_expected_mutbl == Mutability::Mut
|
||||
&& alloc_actual_mutbl == Mutability::Not
|
||||
@ -842,9 +843,16 @@ fn visit_scalar(
|
||||
}
|
||||
|
||||
fn in_mutable_memory(&self, val: &PlaceTy<'tcx, M::Provenance>) -> bool {
|
||||
debug_assert!(self.ctfe_mode.is_some());
|
||||
if let Some(mplace) = val.as_mplace_or_local().left() {
|
||||
if let Some(alloc_id) = mplace.ptr().provenance.and_then(|p| p.get_alloc_id()) {
|
||||
mutability(self.ecx, alloc_id).is_mut()
|
||||
let tcx = *self.ecx.tcx;
|
||||
// Everything must be already interned.
|
||||
let mutbl = tcx.global_alloc(alloc_id).mutability(tcx, self.ecx.param_env);
|
||||
if let Some((_, alloc)) = self.ecx.memory.alloc_map.get(alloc_id) {
|
||||
assert_eq!(alloc.mutability, mutbl);
|
||||
}
|
||||
mutbl.is_mut()
|
||||
} else {
|
||||
// No memory at all.
|
||||
false
|
||||
@ -1016,53 +1024,6 @@ fn union_data_range_uncached<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether the allocation is mutable, and whether it's actually a static.
|
||||
/// For "root" statics we look at the type to account for interior
|
||||
/// mutability; for nested statics we have no type and directly use the annotated mutability.
|
||||
fn mutability<'tcx>(ecx: &InterpCx<'tcx, impl Machine<'tcx>>, alloc_id: AllocId) -> Mutability {
|
||||
// Let's see what kind of memory this points to.
|
||||
// We're not using `try_global_alloc` since dangling pointers have already been handled.
|
||||
match ecx.tcx.global_alloc(alloc_id) {
|
||||
GlobalAlloc::Static(did) => {
|
||||
let DefKind::Static { safety: _, mutability, nested } = ecx.tcx.def_kind(did) else {
|
||||
bug!()
|
||||
};
|
||||
if nested {
|
||||
assert!(
|
||||
ecx.memory.alloc_map.get(alloc_id).is_none(),
|
||||
"allocations of nested statics are already interned: {alloc_id:?}, {did:?}"
|
||||
);
|
||||
// Nested statics in a `static` are never interior mutable,
|
||||
// so just use the declared mutability.
|
||||
mutability
|
||||
} else {
|
||||
let mutability = match mutability {
|
||||
Mutability::Not
|
||||
if !ecx
|
||||
.tcx
|
||||
.type_of(did)
|
||||
.no_bound_vars()
|
||||
.expect("statics should not have generic parameters")
|
||||
.is_freeze(*ecx.tcx, ty::ParamEnv::reveal_all()) =>
|
||||
{
|
||||
Mutability::Mut
|
||||
}
|
||||
_ => mutability,
|
||||
};
|
||||
if let Some((_, alloc)) = ecx.memory.alloc_map.get(alloc_id) {
|
||||
assert_eq!(alloc.mutability, mutability);
|
||||
}
|
||||
mutability
|
||||
}
|
||||
}
|
||||
GlobalAlloc::Memory(alloc) => alloc.inner().mutability,
|
||||
GlobalAlloc::Function { .. } | GlobalAlloc::VTable(..) => {
|
||||
// These are immutable, we better don't allow mutable pointers here.
|
||||
Mutability::Not
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, 'tcx, M> {
|
||||
type V = PlaceTy<'tcx, M::Provenance>;
|
||||
|
||||
|
@ -937,7 +937,7 @@ fn usage(verbose: bool, include_unstable_options: bool, nightly_build: bool) {
|
||||
let groups = if verbose { config::rustc_optgroups() } else { config::rustc_short_optgroups() };
|
||||
let mut options = getopts::Options::new();
|
||||
for option in groups.iter().filter(|x| include_unstable_options || x.is_stable()) {
|
||||
(option.apply)(&mut options);
|
||||
option.apply(&mut options);
|
||||
}
|
||||
let message = "Usage: rustc [OPTIONS] INPUT";
|
||||
let nightly_help = if nightly_build {
|
||||
@ -1219,7 +1219,7 @@ pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option<geto
|
||||
let mut options = getopts::Options::new();
|
||||
let optgroups = config::rustc_optgroups();
|
||||
for option in &optgroups {
|
||||
(option.apply)(&mut options);
|
||||
option.apply(&mut options);
|
||||
}
|
||||
let matches = options.parse(args).unwrap_or_else(|e| {
|
||||
let msg: Option<String> = match e {
|
||||
@ -1233,7 +1233,7 @@ pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option<geto
|
||||
optgroups.iter().find(|option| option.name == opt).map(|option| {
|
||||
// Print the help just for the option in question.
|
||||
let mut options = getopts::Options::new();
|
||||
(option.apply)(&mut options);
|
||||
option.apply(&mut options);
|
||||
// getopt requires us to pass a function for joining an iterator of
|
||||
// strings, even though in this case we expect exactly one string.
|
||||
options.usage_with_format(|it| {
|
||||
|
@ -336,6 +336,7 @@ pub fn internal(&self, feature: Symbol) -> bool {
|
||||
(unstable, riscv_target_feature, "1.45.0", Some(44839)),
|
||||
(unstable, rtm_target_feature, "1.35.0", Some(44839)),
|
||||
(unstable, s390x_target_feature, "1.82.0", Some(44839)),
|
||||
(unstable, sparc_target_feature, "CURRENT_RUSTC_VERSION", Some(132783)),
|
||||
(unstable, sse4a_target_feature, "1.27.0", Some(44839)),
|
||||
(unstable, tbm_target_feature, "1.27.0", Some(44839)),
|
||||
(unstable, wasm_target_feature, "1.30.0", Some(44839)),
|
||||
|
@ -5,13 +5,14 @@
|
||||
use rustc_data_structures::unord::{UnordMap, UnordSet};
|
||||
use rustc_errors::MultiSpan;
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_hir::Node;
|
||||
use rustc_hir::def::{CtorKind, DefKind};
|
||||
use rustc_hir::{Node, intravisit};
|
||||
use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
|
||||
use rustc_infer::traits::Obligation;
|
||||
use rustc_infer::traits::{Obligation, ObligationCauseCode};
|
||||
use rustc_lint_defs::builtin::{
|
||||
REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS,
|
||||
};
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
|
||||
use rustc_middle::middle::stability::EvalResult;
|
||||
use rustc_middle::span_bug;
|
||||
@ -190,7 +191,7 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
/// Checks that an opaque type does not contain cycles and does not use `Self` or `T::Foo`
|
||||
/// projections that would result in "inheriting lifetimes".
|
||||
fn check_opaque(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
let hir::OpaqueTy { origin, .. } = tcx.hir().expect_opaque_ty(def_id);
|
||||
let hir::OpaqueTy { origin, .. } = *tcx.hir().expect_opaque_ty(def_id);
|
||||
|
||||
// HACK(jynelson): trying to infer the type of `impl trait` breaks documenting
|
||||
// `async-std` (and `pub async fn` in general).
|
||||
@ -200,23 +201,20 @@ fn check_opaque(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
return;
|
||||
}
|
||||
|
||||
let span = tcx.def_span(def_id);
|
||||
|
||||
if tcx.type_of(def_id).instantiate_identity().references_error() {
|
||||
return;
|
||||
}
|
||||
if check_opaque_for_cycles(tcx, def_id, span).is_err() {
|
||||
if check_opaque_for_cycles(tcx, def_id).is_err() {
|
||||
return;
|
||||
}
|
||||
|
||||
let _ = check_opaque_meets_bounds(tcx, def_id, span, origin);
|
||||
let _ = check_opaque_meets_bounds(tcx, def_id, origin);
|
||||
}
|
||||
|
||||
/// Checks that an opaque type does not contain cycles.
|
||||
pub(super) fn check_opaque_for_cycles<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
span: Span,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
let args = GenericArgs::identity_for_item(tcx, def_id);
|
||||
|
||||
@ -233,7 +231,7 @@ pub(super) fn check_opaque_for_cycles<'tcx>(
|
||||
.try_expand_impl_trait_type(def_id.to_def_id(), args, InspectCoroutineFields::No)
|
||||
.is_err()
|
||||
{
|
||||
let reported = opaque_type_cycle_error(tcx, def_id, span);
|
||||
let reported = opaque_type_cycle_error(tcx, def_id);
|
||||
return Err(reported);
|
||||
}
|
||||
|
||||
@ -267,10 +265,16 @@ pub(super) fn check_opaque_for_cycles<'tcx>(
|
||||
fn check_opaque_meets_bounds<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
span: Span,
|
||||
origin: &hir::OpaqueTyOrigin<LocalDefId>,
|
||||
origin: hir::OpaqueTyOrigin<LocalDefId>,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
let defining_use_anchor = match *origin {
|
||||
let (span, definition_def_id) =
|
||||
if let Some((span, def_id)) = best_definition_site_of_opaque(tcx, def_id, origin) {
|
||||
(span, Some(def_id))
|
||||
} else {
|
||||
(tcx.def_span(def_id), None)
|
||||
};
|
||||
|
||||
let defining_use_anchor = match origin {
|
||||
hir::OpaqueTyOrigin::FnReturn { parent, .. }
|
||||
| hir::OpaqueTyOrigin::AsyncFn { parent, .. }
|
||||
| hir::OpaqueTyOrigin::TyAlias { parent, .. } => parent,
|
||||
@ -281,7 +285,7 @@ fn check_opaque_meets_bounds<'tcx>(
|
||||
let infcx = tcx.infer_ctxt().build(TypingMode::analysis_in_body(tcx, defining_use_anchor));
|
||||
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
|
||||
|
||||
let args = match *origin {
|
||||
let args = match origin {
|
||||
hir::OpaqueTyOrigin::FnReturn { parent, .. }
|
||||
| hir::OpaqueTyOrigin::AsyncFn { parent, .. }
|
||||
| hir::OpaqueTyOrigin::TyAlias { parent, .. } => GenericArgs::identity_for_item(
|
||||
@ -306,8 +310,33 @@ fn check_opaque_meets_bounds<'tcx>(
|
||||
_ => re,
|
||||
});
|
||||
|
||||
let misc_cause = traits::ObligationCause::misc(span, def_id);
|
||||
// HACK: We eagerly instantiate some bounds to report better errors for them...
|
||||
// This isn't necessary for correctness, since we register these bounds when
|
||||
// equating the opaque below, but we should clean this up in the new solver.
|
||||
for (predicate, pred_span) in
|
||||
tcx.explicit_item_bounds(def_id).iter_instantiated_copied(tcx, args)
|
||||
{
|
||||
let predicate = predicate.fold_with(&mut BottomUpFolder {
|
||||
tcx,
|
||||
ty_op: |ty| if ty == opaque_ty { hidden_ty } else { ty },
|
||||
lt_op: |lt| lt,
|
||||
ct_op: |ct| ct,
|
||||
});
|
||||
|
||||
ocx.register_obligation(Obligation::new(
|
||||
tcx,
|
||||
ObligationCause::new(
|
||||
span,
|
||||
def_id,
|
||||
ObligationCauseCode::OpaqueTypeBound(pred_span, definition_def_id),
|
||||
),
|
||||
param_env,
|
||||
predicate,
|
||||
));
|
||||
}
|
||||
|
||||
let misc_cause = ObligationCause::misc(span, def_id);
|
||||
// FIXME: We should just register the item bounds here, rather than equating.
|
||||
match ocx.eq(&misc_cause, param_env, opaque_ty, hidden_ty) {
|
||||
Ok(()) => {}
|
||||
Err(ty_err) => {
|
||||
@ -364,6 +393,97 @@ fn check_opaque_meets_bounds<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
fn best_definition_site_of_opaque<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
opaque_def_id: LocalDefId,
|
||||
origin: hir::OpaqueTyOrigin<LocalDefId>,
|
||||
) -> Option<(Span, LocalDefId)> {
|
||||
struct TaitConstraintLocator<'tcx> {
|
||||
opaque_def_id: LocalDefId,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
impl<'tcx> TaitConstraintLocator<'tcx> {
|
||||
fn check(&self, item_def_id: LocalDefId) -> ControlFlow<(Span, LocalDefId)> {
|
||||
if !self.tcx.has_typeck_results(item_def_id) {
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
|
||||
if let Some(hidden_ty) =
|
||||
self.tcx.mir_borrowck(item_def_id).concrete_opaque_types.get(&self.opaque_def_id)
|
||||
{
|
||||
ControlFlow::Break((hidden_ty.span, item_def_id))
|
||||
} else {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> {
|
||||
type NestedFilter = nested_filter::All;
|
||||
type Result = ControlFlow<(Span, LocalDefId)>;
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
self.tcx.hir()
|
||||
}
|
||||
fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) -> Self::Result {
|
||||
if let hir::ExprKind::Closure(closure) = ex.kind {
|
||||
self.check(closure.def_id)?;
|
||||
}
|
||||
intravisit::walk_expr(self, ex)
|
||||
}
|
||||
fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) -> Self::Result {
|
||||
self.check(it.owner_id.def_id)?;
|
||||
intravisit::walk_item(self, it)
|
||||
}
|
||||
fn visit_impl_item(&mut self, it: &'tcx hir::ImplItem<'tcx>) -> Self::Result {
|
||||
self.check(it.owner_id.def_id)?;
|
||||
intravisit::walk_impl_item(self, it)
|
||||
}
|
||||
fn visit_trait_item(&mut self, it: &'tcx hir::TraitItem<'tcx>) -> Self::Result {
|
||||
self.check(it.owner_id.def_id)?;
|
||||
intravisit::walk_trait_item(self, it)
|
||||
}
|
||||
fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) -> Self::Result {
|
||||
intravisit::walk_foreign_item(self, it)
|
||||
}
|
||||
}
|
||||
|
||||
let mut locator = TaitConstraintLocator { tcx, opaque_def_id };
|
||||
match origin {
|
||||
hir::OpaqueTyOrigin::FnReturn { parent, .. }
|
||||
| hir::OpaqueTyOrigin::AsyncFn { parent, .. } => locator.check(parent).break_value(),
|
||||
hir::OpaqueTyOrigin::TyAlias { parent, in_assoc_ty: true } => {
|
||||
let impl_def_id = tcx.local_parent(parent);
|
||||
for assoc in tcx.associated_items(impl_def_id).in_definition_order() {
|
||||
match assoc.kind {
|
||||
ty::AssocKind::Const | ty::AssocKind::Fn => {
|
||||
if let ControlFlow::Break(span) = locator.check(assoc.def_id.expect_local())
|
||||
{
|
||||
return Some(span);
|
||||
}
|
||||
}
|
||||
ty::AssocKind::Type => {}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false, .. } => {
|
||||
let scope = tcx.hir().get_defining_scope(tcx.local_def_id_to_hir_id(opaque_def_id));
|
||||
let found = if scope == hir::CRATE_HIR_ID {
|
||||
tcx.hir().walk_toplevel_module(&mut locator)
|
||||
} else {
|
||||
match tcx.hir_node(scope) {
|
||||
Node::Item(it) => locator.visit_item(it),
|
||||
Node::ImplItem(it) => locator.visit_impl_item(it),
|
||||
Node::TraitItem(it) => locator.visit_trait_item(it),
|
||||
Node::ForeignItem(it) => locator.visit_foreign_item(it),
|
||||
other => bug!("{:?} is not a valid scope for an opaque type item", other),
|
||||
}
|
||||
};
|
||||
found.break_value()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn sanity_check_found_hidden_type<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
key: ty::OpaqueTypeKey<'tcx>,
|
||||
@ -1535,11 +1655,8 @@ fn check_type_alias_type_params_are_used<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalD
|
||||
///
|
||||
/// If all the return expressions evaluate to `!`, then we explain that the error will go away
|
||||
/// after changing it. This can happen when a user uses `panic!()` or similar as a placeholder.
|
||||
fn opaque_type_cycle_error(
|
||||
tcx: TyCtxt<'_>,
|
||||
opaque_def_id: LocalDefId,
|
||||
span: Span,
|
||||
) -> ErrorGuaranteed {
|
||||
fn opaque_type_cycle_error(tcx: TyCtxt<'_>, opaque_def_id: LocalDefId) -> ErrorGuaranteed {
|
||||
let span = tcx.def_span(opaque_def_id);
|
||||
let mut err = struct_span_code_err!(tcx.dcx(), span, E0720, "cannot resolve opaque type");
|
||||
|
||||
let mut label = false;
|
||||
|
@ -100,9 +100,9 @@ fn impl_into_iterator_should_be_iterator(
|
||||
ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
unsatisfied_predicates: &Vec<(
|
||||
ty::Predicate<'_>,
|
||||
Option<ty::Predicate<'_>>,
|
||||
Option<ObligationCause<'_>>,
|
||||
ty::Predicate<'tcx>,
|
||||
Option<ty::Predicate<'tcx>>,
|
||||
Option<ObligationCause<'tcx>>,
|
||||
)>,
|
||||
) -> bool {
|
||||
fn predicate_bounds_generic_param<'tcx>(
|
||||
@ -131,15 +131,17 @@ fn predicate_bounds_generic_param<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
fn is_iterator_predicate(predicate: ty::Predicate<'_>, tcx: TyCtxt<'_>) -> bool {
|
||||
let is_iterator_predicate = |predicate: ty::Predicate<'tcx>| -> bool {
|
||||
if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) =
|
||||
predicate.kind().as_ref().skip_binder()
|
||||
{
|
||||
tcx.is_diagnostic_item(sym::Iterator, trait_pred.trait_ref.def_id)
|
||||
self.tcx.is_diagnostic_item(sym::Iterator, trait_pred.trait_ref.def_id)
|
||||
// ignore unsatisfied predicates generated from trying to auto-ref ty (#127511)
|
||||
&& trait_pred.trait_ref.self_ty() == ty
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Does the `ty` implement `IntoIterator`?
|
||||
let Some(into_iterator_trait) = self.tcx.get_diagnostic_item(sym::IntoIterator) else {
|
||||
@ -164,7 +166,7 @@ fn is_iterator_predicate(predicate: ty::Predicate<'_>, tcx: TyCtxt<'_>) -> bool
|
||||
generics,
|
||||
generic_param,
|
||||
self.tcx,
|
||||
) && is_iterator_predicate(unsatisfied.0, self.tcx)
|
||||
) && is_iterator_predicate(unsatisfied.0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -172,7 +174,7 @@ fn is_iterator_predicate(predicate: ty::Predicate<'_>, tcx: TyCtxt<'_>) -> bool
|
||||
}
|
||||
ty::Slice(..) | ty::Adt(..) | ty::Alias(ty::Opaque, _) => {
|
||||
for unsatisfied in unsatisfied_predicates.iter() {
|
||||
if is_iterator_predicate(unsatisfied.0, self.tcx) {
|
||||
if is_iterator_predicate(unsatisfied.0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -104,6 +104,7 @@ pub fn register_region_obligation_with_cause(
|
||||
infer::RelateParamBound(cause.span, sup_type, match cause.code().peel_derives() {
|
||||
ObligationCauseCode::WhereClause(_, span)
|
||||
| ObligationCauseCode::WhereClauseInExpr(_, span, ..)
|
||||
| ObligationCauseCode::OpaqueTypeBound(span, _)
|
||||
if !span.is_dummy() =>
|
||||
{
|
||||
Some(*span)
|
||||
|
@ -102,7 +102,7 @@ fn new_public_extern_entry<S, I>(locations: I) -> ExternEntry
|
||||
fn optgroups() -> getopts::Options {
|
||||
let mut opts = getopts::Options::new();
|
||||
for group in rustc_optgroups() {
|
||||
(group.apply)(&mut opts);
|
||||
group.apply(&mut opts);
|
||||
}
|
||||
return opts;
|
||||
}
|
||||
|
@ -715,7 +715,17 @@ fn lifetime_or_char(&mut self) -> TokenKind {
|
||||
self.bump();
|
||||
self.bump();
|
||||
self.eat_while(is_id_continue);
|
||||
return RawLifetime;
|
||||
match self.first() {
|
||||
'\'' => {
|
||||
// Check if after skipping literal contents we've met a closing
|
||||
// single quote (which means that user attempted to create a
|
||||
// string with single quotes).
|
||||
self.bump();
|
||||
let kind = Char { terminated: true };
|
||||
return Literal { kind, suffix_start: self.pos_within_token() };
|
||||
}
|
||||
_ => return RawLifetime,
|
||||
}
|
||||
}
|
||||
|
||||
// Either a lifetime or a character literal with
|
||||
|
@ -1,5 +1,9 @@
|
||||
#include "LLVMWrapper.h"
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/ProfileData/Coverage/CoverageMapping.h"
|
||||
#include "llvm/ProfileData/Coverage/CoverageMappingWriter.h"
|
||||
#include "llvm/ProfileData/InstrProf.h"
|
||||
|
@ -1,31 +1,12 @@
|
||||
#ifndef INCLUDED_RUSTC_LLVM_LLVMWRAPPER_H
|
||||
#define INCLUDED_RUSTC_LLVM_LLVMWRAPPER_H
|
||||
|
||||
#include "SuppressLLVMWarnings.h"
|
||||
|
||||
#include "llvm-c/BitReader.h"
|
||||
#include "llvm-c/Core.h"
|
||||
#include "llvm-c/Object.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Analysis/Lint.h"
|
||||
#include "llvm/Analysis/Passes.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/InlineAsm.h"
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/DynamicLibrary.h"
|
||||
#include "llvm/Support/FormattedStream.h"
|
||||
#include "llvm/Support/JSON.h"
|
||||
#include "llvm/Support/Memory.h"
|
||||
#include "llvm/Support/SourceMgr.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
#include "llvm/Support/Timer.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Target/TargetOptions.h"
|
||||
#include "llvm/Transforms/IPO.h"
|
||||
#include "llvm/Transforms/Scalar.h"
|
||||
#include "llvm/Config/llvm-config.h" // LLVM_VERSION_MAJOR, LLVM_VERSION_MINOR
|
||||
#include "llvm/Support/raw_ostream.h" // llvm::raw_ostream
|
||||
#include <cstddef> // size_t etc
|
||||
#include <cstdint> // uint64_t etc
|
||||
|
||||
#define LLVM_VERSION_GE(major, minor) \
|
||||
(LLVM_VERSION_MAJOR > (major) || \
|
||||
@ -33,79 +14,17 @@
|
||||
|
||||
#define LLVM_VERSION_LT(major, minor) (!LLVM_VERSION_GE((major), (minor)))
|
||||
|
||||
#if LLVM_VERSION_GE(20, 0)
|
||||
#include "llvm/Transforms/Utils/Instrumentation.h"
|
||||
#else
|
||||
#include "llvm/Transforms/Instrumentation.h"
|
||||
#endif
|
||||
|
||||
#include "llvm/IR/LegacyPassManager.h"
|
||||
|
||||
#include "llvm/Bitcode/BitcodeReader.h"
|
||||
#include "llvm/Bitcode/BitcodeWriter.h"
|
||||
|
||||
#include "llvm/IR/DIBuilder.h"
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#include "llvm/IR/IRPrintingPasses.h"
|
||||
#include "llvm/Linker/Linker.h"
|
||||
|
||||
#include "llvm/TargetParser/Triple.h"
|
||||
|
||||
extern "C" void LLVMRustSetLastError(const char *);
|
||||
|
||||
enum class LLVMRustResult { Success, Failure };
|
||||
|
||||
enum LLVMRustAttribute {
|
||||
AlwaysInline = 0,
|
||||
ByVal = 1,
|
||||
Cold = 2,
|
||||
InlineHint = 3,
|
||||
MinSize = 4,
|
||||
Naked = 5,
|
||||
NoAlias = 6,
|
||||
NoCapture = 7,
|
||||
NoInline = 8,
|
||||
NonNull = 9,
|
||||
NoRedZone = 10,
|
||||
NoReturn = 11,
|
||||
NoUnwind = 12,
|
||||
OptimizeForSize = 13,
|
||||
ReadOnly = 14,
|
||||
SExt = 15,
|
||||
StructRet = 16,
|
||||
UWTable = 17,
|
||||
ZExt = 18,
|
||||
InReg = 19,
|
||||
SanitizeThread = 20,
|
||||
SanitizeAddress = 21,
|
||||
SanitizeMemory = 22,
|
||||
NonLazyBind = 23,
|
||||
OptimizeNone = 24,
|
||||
ReadNone = 26,
|
||||
SanitizeHWAddress = 28,
|
||||
WillReturn = 29,
|
||||
StackProtectReq = 30,
|
||||
StackProtectStrong = 31,
|
||||
StackProtect = 32,
|
||||
NoUndef = 33,
|
||||
SanitizeMemTag = 34,
|
||||
NoCfCheck = 35,
|
||||
ShadowCallStack = 36,
|
||||
AllocSize = 37,
|
||||
AllocatedPointer = 38,
|
||||
AllocAlign = 39,
|
||||
SanitizeSafeStack = 40,
|
||||
FnRetThunkExtern = 41,
|
||||
Writable = 42,
|
||||
DeadOnUnwind = 43,
|
||||
};
|
||||
|
||||
typedef struct OpaqueRustString *RustStringRef;
|
||||
typedef struct LLVMOpaqueTwine *LLVMTwineRef;
|
||||
typedef struct LLVMOpaqueSMDiagnostic *LLVMSMDiagnosticRef;
|
||||
|
||||
extern "C" void LLVMRustStringWriteImpl(RustStringRef Str, const char *Ptr,
|
||||
size_t Size);
|
||||
extern "C" void LLVMRustStringWriteImpl(RustStringRef buf,
|
||||
const char *slice_ptr,
|
||||
size_t slice_len);
|
||||
|
||||
class RawRustStringOstream : public llvm::raw_ostream {
|
||||
RustStringRef Str;
|
||||
@ -126,3 +45,5 @@ public:
|
||||
flush();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // INCLUDED_RUSTC_LLVM_LLVMWRAPPER_H
|
||||
|
@ -1,8 +1,10 @@
|
||||
#include "llvm/Linker/Linker.h"
|
||||
#include "SuppressLLVMWarnings.h"
|
||||
|
||||
#include "LLVMWrapper.h"
|
||||
|
||||
#include "llvm/Bitcode/BitcodeReader.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Linker/Linker.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
struct RustLinker {
|
||||
|
@ -1,25 +1,21 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <iomanip>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include "LLVMWrapper.h"
|
||||
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm-c/Core.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Analysis/Lint.h"
|
||||
#include "llvm/Analysis/TargetLibraryInfo.h"
|
||||
#include "llvm/Analysis/TargetTransformInfo.h"
|
||||
#include "llvm/Bitcode/BitcodeWriter.h"
|
||||
#include "llvm/CodeGen/CommandFlags.h"
|
||||
#include "llvm/CodeGen/TargetSubtargetInfo.h"
|
||||
#include "llvm/IR/AssemblyAnnotationWriter.h"
|
||||
#include "llvm/IR/AutoUpgrade.h"
|
||||
#include "llvm/IR/IntrinsicInst.h"
|
||||
#include "llvm/IR/LegacyPassManager.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include "llvm/IR/Verifier.h"
|
||||
#include "llvm/LTO/LTO.h"
|
||||
#include "llvm/MC/MCSubtargetInfo.h"
|
||||
#include "llvm/MC/TargetRegistry.h"
|
||||
#include "llvm/Object/IRObjectFile.h"
|
||||
#include "llvm/Object/ObjectFile.h"
|
||||
#include "llvm/Passes/PassBuilder.h"
|
||||
#include "llvm/Passes/PassPlugin.h"
|
||||
@ -30,25 +26,28 @@
|
||||
#include "llvm/Support/VirtualFileSystem.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/TargetParser/Host.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/Instrumentation/AddressSanitizer.h"
|
||||
#include "llvm/Transforms/Instrumentation/DataFlowSanitizer.h"
|
||||
#include "llvm/Transforms/Utils/AddDiscriminators.h"
|
||||
#include "llvm/Transforms/Utils/FunctionImportUtils.h"
|
||||
#if LLVM_VERSION_GE(19, 0)
|
||||
#include "llvm/Support/PGOOptions.h"
|
||||
#endif
|
||||
#include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h"
|
||||
#include "llvm/Transforms/Instrumentation/InstrProfiling.h"
|
||||
#include "llvm/Transforms/Instrumentation/MemorySanitizer.h"
|
||||
#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
|
||||
#include "llvm/Transforms/Utils.h"
|
||||
#include "llvm/Transforms/Utils/CanonicalizeAliases.h"
|
||||
#include "llvm/Transforms/Utils/FunctionImportUtils.h"
|
||||
#include "llvm/Transforms/Utils/NameAnonGlobals.h"
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// Conditional includes prevent clang-format from fully sorting the list,
|
||||
// so keep them separate.
|
||||
#if LLVM_VERSION_GE(19, 0)
|
||||
#include "llvm/Support/PGOOptions.h"
|
||||
#endif
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
@ -1624,5 +1623,6 @@ extern "C" void LLVMRustComputeLTOCacheKey(RustStringRef KeyOut,
|
||||
CfiFunctionDefs, CfiFunctionDecls);
|
||||
#endif
|
||||
|
||||
LLVMRustStringWriteImpl(KeyOut, Key.c_str(), Key.size());
|
||||
auto OS = RawRustStringOstream(KeyOut);
|
||||
OS << Key.str();
|
||||
}
|
||||
|
@ -1,28 +1,38 @@
|
||||
#include "LLVMWrapper.h"
|
||||
|
||||
#include "llvm-c/Core.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/BinaryFormat/Magic.h"
|
||||
#include "llvm/Bitcode/BitcodeWriter.h"
|
||||
#include "llvm/IR/DIBuilder.h"
|
||||
#include "llvm/IR/DebugInfoMetadata.h"
|
||||
#include "llvm/IR/DiagnosticHandler.h"
|
||||
#include "llvm/IR/DiagnosticInfo.h"
|
||||
#include "llvm/IR/DiagnosticPrinter.h"
|
||||
#include "llvm/IR/GlobalVariable.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/InlineAsm.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/Intrinsics.h"
|
||||
#include "llvm/IR/IntrinsicsARM.h"
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
#include "llvm/IR/LLVMRemarkStreamer.h"
|
||||
#include "llvm/IR/Mangler.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/IR/Value.h"
|
||||
#include "llvm/Object/Archive.h"
|
||||
#include "llvm/Object/COFFImportFile.h"
|
||||
#include "llvm/Object/ObjectFile.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Remarks/RemarkFormat.h"
|
||||
#include "llvm/Remarks/RemarkSerializer.h"
|
||||
#include "llvm/Remarks/RemarkStreamer.h"
|
||||
#include "llvm/Support/Compression.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/JSON.h"
|
||||
#include "llvm/Support/ModRef.h"
|
||||
#include "llvm/Support/Signals.h"
|
||||
#include "llvm/Support/Timer.h"
|
||||
#include "llvm/Support/ToolOutputFile.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
// for raw `write` in the bad-alloc handler
|
||||
@ -216,94 +226,140 @@ extern "C" LLVMValueRef LLVMRustInsertPrivateGlobal(LLVMModuleRef M,
|
||||
GlobalValue::PrivateLinkage, nullptr));
|
||||
}
|
||||
|
||||
static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) {
|
||||
// Must match the layout of `rustc_codegen_llvm::llvm::ffi::AttributeKind`.
|
||||
enum class LLVMRustAttributeKind {
|
||||
AlwaysInline = 0,
|
||||
ByVal = 1,
|
||||
Cold = 2,
|
||||
InlineHint = 3,
|
||||
MinSize = 4,
|
||||
Naked = 5,
|
||||
NoAlias = 6,
|
||||
NoCapture = 7,
|
||||
NoInline = 8,
|
||||
NonNull = 9,
|
||||
NoRedZone = 10,
|
||||
NoReturn = 11,
|
||||
NoUnwind = 12,
|
||||
OptimizeForSize = 13,
|
||||
ReadOnly = 14,
|
||||
SExt = 15,
|
||||
StructRet = 16,
|
||||
UWTable = 17,
|
||||
ZExt = 18,
|
||||
InReg = 19,
|
||||
SanitizeThread = 20,
|
||||
SanitizeAddress = 21,
|
||||
SanitizeMemory = 22,
|
||||
NonLazyBind = 23,
|
||||
OptimizeNone = 24,
|
||||
ReadNone = 26,
|
||||
SanitizeHWAddress = 28,
|
||||
WillReturn = 29,
|
||||
StackProtectReq = 30,
|
||||
StackProtectStrong = 31,
|
||||
StackProtect = 32,
|
||||
NoUndef = 33,
|
||||
SanitizeMemTag = 34,
|
||||
NoCfCheck = 35,
|
||||
ShadowCallStack = 36,
|
||||
AllocSize = 37,
|
||||
AllocatedPointer = 38,
|
||||
AllocAlign = 39,
|
||||
SanitizeSafeStack = 40,
|
||||
FnRetThunkExtern = 41,
|
||||
Writable = 42,
|
||||
DeadOnUnwind = 43,
|
||||
};
|
||||
|
||||
static Attribute::AttrKind fromRust(LLVMRustAttributeKind Kind) {
|
||||
switch (Kind) {
|
||||
case AlwaysInline:
|
||||
case LLVMRustAttributeKind::AlwaysInline:
|
||||
return Attribute::AlwaysInline;
|
||||
case ByVal:
|
||||
case LLVMRustAttributeKind::ByVal:
|
||||
return Attribute::ByVal;
|
||||
case Cold:
|
||||
case LLVMRustAttributeKind::Cold:
|
||||
return Attribute::Cold;
|
||||
case InlineHint:
|
||||
case LLVMRustAttributeKind::InlineHint:
|
||||
return Attribute::InlineHint;
|
||||
case MinSize:
|
||||
case LLVMRustAttributeKind::MinSize:
|
||||
return Attribute::MinSize;
|
||||
case Naked:
|
||||
case LLVMRustAttributeKind::Naked:
|
||||
return Attribute::Naked;
|
||||
case NoAlias:
|
||||
case LLVMRustAttributeKind::NoAlias:
|
||||
return Attribute::NoAlias;
|
||||
case NoCapture:
|
||||
case LLVMRustAttributeKind::NoCapture:
|
||||
return Attribute::NoCapture;
|
||||
case NoCfCheck:
|
||||
case LLVMRustAttributeKind::NoCfCheck:
|
||||
return Attribute::NoCfCheck;
|
||||
case NoInline:
|
||||
case LLVMRustAttributeKind::NoInline:
|
||||
return Attribute::NoInline;
|
||||
case NonNull:
|
||||
case LLVMRustAttributeKind::NonNull:
|
||||
return Attribute::NonNull;
|
||||
case NoRedZone:
|
||||
case LLVMRustAttributeKind::NoRedZone:
|
||||
return Attribute::NoRedZone;
|
||||
case NoReturn:
|
||||
case LLVMRustAttributeKind::NoReturn:
|
||||
return Attribute::NoReturn;
|
||||
case NoUnwind:
|
||||
case LLVMRustAttributeKind::NoUnwind:
|
||||
return Attribute::NoUnwind;
|
||||
case OptimizeForSize:
|
||||
case LLVMRustAttributeKind::OptimizeForSize:
|
||||
return Attribute::OptimizeForSize;
|
||||
case ReadOnly:
|
||||
case LLVMRustAttributeKind::ReadOnly:
|
||||
return Attribute::ReadOnly;
|
||||
case SExt:
|
||||
case LLVMRustAttributeKind::SExt:
|
||||
return Attribute::SExt;
|
||||
case StructRet:
|
||||
case LLVMRustAttributeKind::StructRet:
|
||||
return Attribute::StructRet;
|
||||
case UWTable:
|
||||
case LLVMRustAttributeKind::UWTable:
|
||||
return Attribute::UWTable;
|
||||
case ZExt:
|
||||
case LLVMRustAttributeKind::ZExt:
|
||||
return Attribute::ZExt;
|
||||
case InReg:
|
||||
case LLVMRustAttributeKind::InReg:
|
||||
return Attribute::InReg;
|
||||
case SanitizeThread:
|
||||
case LLVMRustAttributeKind::SanitizeThread:
|
||||
return Attribute::SanitizeThread;
|
||||
case SanitizeAddress:
|
||||
case LLVMRustAttributeKind::SanitizeAddress:
|
||||
return Attribute::SanitizeAddress;
|
||||
case SanitizeMemory:
|
||||
case LLVMRustAttributeKind::SanitizeMemory:
|
||||
return Attribute::SanitizeMemory;
|
||||
case NonLazyBind:
|
||||
case LLVMRustAttributeKind::NonLazyBind:
|
||||
return Attribute::NonLazyBind;
|
||||
case OptimizeNone:
|
||||
case LLVMRustAttributeKind::OptimizeNone:
|
||||
return Attribute::OptimizeNone;
|
||||
case ReadNone:
|
||||
case LLVMRustAttributeKind::ReadNone:
|
||||
return Attribute::ReadNone;
|
||||
case SanitizeHWAddress:
|
||||
case LLVMRustAttributeKind::SanitizeHWAddress:
|
||||
return Attribute::SanitizeHWAddress;
|
||||
case WillReturn:
|
||||
case LLVMRustAttributeKind::WillReturn:
|
||||
return Attribute::WillReturn;
|
||||
case StackProtectReq:
|
||||
case LLVMRustAttributeKind::StackProtectReq:
|
||||
return Attribute::StackProtectReq;
|
||||
case StackProtectStrong:
|
||||
case LLVMRustAttributeKind::StackProtectStrong:
|
||||
return Attribute::StackProtectStrong;
|
||||
case StackProtect:
|
||||
case LLVMRustAttributeKind::StackProtect:
|
||||
return Attribute::StackProtect;
|
||||
case NoUndef:
|
||||
case LLVMRustAttributeKind::NoUndef:
|
||||
return Attribute::NoUndef;
|
||||
case SanitizeMemTag:
|
||||
case LLVMRustAttributeKind::SanitizeMemTag:
|
||||
return Attribute::SanitizeMemTag;
|
||||
case ShadowCallStack:
|
||||
case LLVMRustAttributeKind::ShadowCallStack:
|
||||
return Attribute::ShadowCallStack;
|
||||
case AllocSize:
|
||||
case LLVMRustAttributeKind::AllocSize:
|
||||
return Attribute::AllocSize;
|
||||
case AllocatedPointer:
|
||||
case LLVMRustAttributeKind::AllocatedPointer:
|
||||
return Attribute::AllocatedPointer;
|
||||
case AllocAlign:
|
||||
case LLVMRustAttributeKind::AllocAlign:
|
||||
return Attribute::AllocAlign;
|
||||
case SanitizeSafeStack:
|
||||
case LLVMRustAttributeKind::SanitizeSafeStack:
|
||||
return Attribute::SafeStack;
|
||||
case FnRetThunkExtern:
|
||||
case LLVMRustAttributeKind::FnRetThunkExtern:
|
||||
return Attribute::FnRetThunkExtern;
|
||||
case Writable:
|
||||
case LLVMRustAttributeKind::Writable:
|
||||
return Attribute::Writable;
|
||||
case DeadOnUnwind:
|
||||
case LLVMRustAttributeKind::DeadOnUnwind:
|
||||
return Attribute::DeadOnUnwind;
|
||||
}
|
||||
report_fatal_error("bad AttributeKind");
|
||||
report_fatal_error("bad LLVMRustAttributeKind");
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -333,7 +389,7 @@ extern "C" void LLVMRustAddCallSiteAttributes(LLVMValueRef Instr,
|
||||
}
|
||||
|
||||
extern "C" LLVMAttributeRef
|
||||
LLVMRustCreateAttrNoValue(LLVMContextRef C, LLVMRustAttribute RustAttr) {
|
||||
LLVMRustCreateAttrNoValue(LLVMContextRef C, LLVMRustAttributeKind RustAttr) {
|
||||
return wrap(Attribute::get(*unwrap(C), fromRust(RustAttr)));
|
||||
}
|
||||
|
||||
@ -1249,6 +1305,14 @@ LLVMRustDIBuilderCreateDebugLocation(unsigned Line, unsigned Column,
|
||||
return wrap(Loc);
|
||||
}
|
||||
|
||||
extern "C" LLVMMetadataRef
|
||||
LLVMRustDILocationCloneWithBaseDiscriminator(LLVMMetadataRef Location,
|
||||
unsigned BD) {
|
||||
DILocation *Loc = unwrapDIPtr<DILocation>(Location);
|
||||
auto NewLoc = Loc->cloneWithBaseDiscriminator(BD);
|
||||
return wrap(NewLoc.has_value() ? NewLoc.value() : nullptr);
|
||||
}
|
||||
|
||||
extern "C" uint64_t LLVMRustDIBuilderCreateOpDeref() {
|
||||
return dwarf::DW_OP_deref;
|
||||
}
|
||||
@ -1510,8 +1574,8 @@ LLVMRustUnpackSMDiagnostic(LLVMSMDiagnosticRef DRef, RustStringRef MessageOut,
|
||||
const SourceMgr &LSM = *D.getSourceMgr();
|
||||
const MemoryBuffer *LBuf =
|
||||
LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(D.getLoc()));
|
||||
LLVMRustStringWriteImpl(BufferOut, LBuf->getBufferStart(),
|
||||
LBuf->getBufferSize());
|
||||
auto BufferOS = RawRustStringOstream(BufferOut);
|
||||
BufferOS << LBuf->getBuffer();
|
||||
|
||||
*LocOut = D.getLoc().getPointer() - LBuf->getBufferStart();
|
||||
|
||||
|
@ -8,14 +8,14 @@
|
||||
// * https://github.com/llvm/llvm-project/blob/ef6d1ec07c693352c4a60dd58db08d2d8558f6ea/llvm/lib/Object/ArchiveWriter.cpp
|
||||
|
||||
#include "LLVMWrapper.h"
|
||||
#include "SuppressLLVMWarnings.h"
|
||||
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
#include "llvm/Object/COFF.h"
|
||||
#include "llvm/Object/COFFImportFile.h"
|
||||
#include "llvm/Object/IRObjectFile.h"
|
||||
#include "llvm/Object/ObjectFile.h"
|
||||
#include <llvm/Support/raw_ostream.h>
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::sys;
|
||||
|
@ -2,42 +2,75 @@
|
||||
#![allow(internal_features)]
|
||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||
#![doc(rust_logo)]
|
||||
#![feature(extern_types)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![warn(unreachable_pub)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
// NOTE: This crate only exists to allow linking on mingw targets.
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::slice;
|
||||
use std::{ptr, slice};
|
||||
|
||||
use libc::{c_char, size_t};
|
||||
use libc::size_t;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct RustString {
|
||||
pub bytes: RefCell<Vec<u8>>,
|
||||
unsafe extern "C" {
|
||||
/// Opaque type that allows C++ code to write bytes to a Rust-side buffer,
|
||||
/// in conjunction with `RawRustStringOstream`. Use this as `&RustString`
|
||||
/// (Rust) and `RustStringRef` (C++) in FFI signatures.
|
||||
pub type RustString;
|
||||
}
|
||||
|
||||
impl RustString {
|
||||
pub fn len(&self) -> usize {
|
||||
self.bytes.borrow().len()
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.bytes.borrow().is_empty()
|
||||
pub fn build_byte_buffer(closure: impl FnOnce(&Self)) -> Vec<u8> {
|
||||
let buf = RustStringInner::default();
|
||||
closure(buf.as_opaque());
|
||||
buf.into_inner()
|
||||
}
|
||||
}
|
||||
|
||||
/// Appending to a Rust string -- used by RawRustStringOstream.
|
||||
/// Underlying implementation of [`RustString`].
|
||||
///
|
||||
/// Having two separate types makes it possible to use the opaque [`RustString`]
|
||||
/// in FFI signatures without `improper_ctypes` warnings. This is a workaround
|
||||
/// for the fact that there is no way to opt out of `improper_ctypes` when
|
||||
/// _declaring_ a type (as opposed to using that type).
|
||||
#[derive(Default)]
|
||||
struct RustStringInner {
|
||||
bytes: RefCell<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl RustStringInner {
|
||||
fn as_opaque(&self) -> &RustString {
|
||||
let ptr: *const RustStringInner = ptr::from_ref(self);
|
||||
// We can't use `ptr::cast` here because extern types are `!Sized`.
|
||||
let ptr = ptr as *const RustString;
|
||||
unsafe { &*ptr }
|
||||
}
|
||||
|
||||
fn from_opaque(opaque: &RustString) -> &Self {
|
||||
// SAFETY: A valid `&RustString` must have been created via `as_opaque`.
|
||||
let ptr: *const RustString = ptr::from_ref(opaque);
|
||||
let ptr: *const RustStringInner = ptr.cast();
|
||||
unsafe { &*ptr }
|
||||
}
|
||||
|
||||
fn into_inner(self) -> Vec<u8> {
|
||||
self.bytes.into_inner()
|
||||
}
|
||||
}
|
||||
|
||||
/// Appends the contents of a byte slice to a [`RustString`].
|
||||
///
|
||||
/// This function is implemented in `rustc_llvm` so that the C++ code in this
|
||||
/// crate can link to it directly, without an implied link-time dependency on
|
||||
/// `rustc_codegen_llvm`.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn LLVMRustStringWriteImpl(
|
||||
sr: &RustString,
|
||||
ptr: *const c_char,
|
||||
size: size_t,
|
||||
buf: &RustString,
|
||||
slice_ptr: *const u8, // Same ABI as `*const c_char`
|
||||
slice_len: size_t,
|
||||
) {
|
||||
let slice = unsafe { slice::from_raw_parts(ptr as *const u8, size) };
|
||||
|
||||
sr.bytes.borrow_mut().extend_from_slice(slice);
|
||||
let slice = unsafe { slice::from_raw_parts(slice_ptr, slice_len) };
|
||||
RustStringInner::from_opaque(buf).bytes.borrow_mut().extend_from_slice(slice);
|
||||
}
|
||||
|
||||
/// Initialize targets enabled by the build script via `cfg(llvm_component = "...")`.
|
||||
|
@ -12,11 +12,12 @@
|
||||
use std::num::NonZero;
|
||||
use std::{fmt, io};
|
||||
|
||||
use rustc_abi::{AddressSpace, Endian, HasDataLayout};
|
||||
use rustc_ast::LitKind;
|
||||
use rustc_abi::{AddressSpace, Align, Endian, HasDataLayout, Size};
|
||||
use rustc_ast::{LitKind, Mutability};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::sync::Lock;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
@ -45,7 +46,7 @@
|
||||
pub use self::value::Scalar;
|
||||
use crate::mir;
|
||||
use crate::ty::codec::{TyDecoder, TyEncoder};
|
||||
use crate::ty::{self, Instance, Ty, TyCtxt};
|
||||
use crate::ty::{self, Instance, ParamEnv, Ty, TyCtxt};
|
||||
|
||||
/// Uniquely identifies one of the following:
|
||||
/// - A constant
|
||||
@ -310,6 +311,85 @@ pub fn address_space(&self, cx: &impl HasDataLayout) -> AddressSpace {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mutability(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Mutability {
|
||||
// Let's see what kind of memory we are.
|
||||
match self {
|
||||
GlobalAlloc::Static(did) => {
|
||||
let DefKind::Static { safety: _, mutability, nested } = tcx.def_kind(did) else {
|
||||
bug!()
|
||||
};
|
||||
if nested {
|
||||
// Nested statics in a `static` are never interior mutable,
|
||||
// so just use the declared mutability.
|
||||
if cfg!(debug_assertions) {
|
||||
let alloc = tcx.eval_static_initializer(did).unwrap();
|
||||
assert_eq!(alloc.0.mutability, mutability);
|
||||
}
|
||||
mutability
|
||||
} else {
|
||||
let mutability = match mutability {
|
||||
Mutability::Not
|
||||
if !tcx
|
||||
.type_of(did)
|
||||
.no_bound_vars()
|
||||
.expect("statics should not have generic parameters")
|
||||
.is_freeze(tcx, param_env) =>
|
||||
{
|
||||
Mutability::Mut
|
||||
}
|
||||
_ => mutability,
|
||||
};
|
||||
mutability
|
||||
}
|
||||
}
|
||||
GlobalAlloc::Memory(alloc) => alloc.inner().mutability,
|
||||
GlobalAlloc::Function { .. } | GlobalAlloc::VTable(..) => {
|
||||
// These are immutable.
|
||||
Mutability::Not
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn size_and_align(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> (Size, Align) {
|
||||
match self {
|
||||
GlobalAlloc::Static(def_id) => {
|
||||
let DefKind::Static { nested, .. } = tcx.def_kind(def_id) else {
|
||||
bug!("GlobalAlloc::Static is not a static")
|
||||
};
|
||||
|
||||
if nested {
|
||||
// Nested anonymous statics are untyped, so let's get their
|
||||
// size and alignment from the allocation itself. This always
|
||||
// succeeds, as the query is fed at DefId creation time, so no
|
||||
// evaluation actually occurs.
|
||||
let alloc = tcx.eval_static_initializer(def_id).unwrap();
|
||||
(alloc.0.size(), alloc.0.align)
|
||||
} else {
|
||||
// Use size and align of the type for everything else. We need
|
||||
// to do that to
|
||||
// * avoid cycle errors in case of self-referential statics,
|
||||
// * be able to get information on extern statics.
|
||||
let ty = tcx
|
||||
.type_of(def_id)
|
||||
.no_bound_vars()
|
||||
.expect("statics should not have generic parameters");
|
||||
let layout = tcx.layout_of(param_env.and(ty)).unwrap();
|
||||
assert!(layout.is_sized());
|
||||
(layout.size, layout.align.abi)
|
||||
}
|
||||
}
|
||||
GlobalAlloc::Memory(alloc) => {
|
||||
let alloc = alloc.inner();
|
||||
(alloc.size(), alloc.align)
|
||||
}
|
||||
GlobalAlloc::Function { .. } => (Size::ZERO, Align::ONE),
|
||||
GlobalAlloc::VTable(..) => {
|
||||
// No data to be accessed here. But vtables are pointer-aligned.
|
||||
return (Size::ZERO, tcx.data_layout.pointer_align.abi);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const CTFE_ALLOC_SALT: usize = 0;
|
||||
|
@ -193,6 +193,11 @@ pub enum ObligationCauseCode<'tcx> {
|
||||
/// The span corresponds to the clause.
|
||||
WhereClause(DefId, Span),
|
||||
|
||||
/// Represents a bound for an opaque we are checking the well-formedness of.
|
||||
/// The def-id corresponds to a specific definition site that we found the
|
||||
/// hidden type from, if any.
|
||||
OpaqueTypeBound(Span, Option<LocalDefId>),
|
||||
|
||||
/// Like `WhereClause`, but also identifies the expression
|
||||
/// which requires the `where` clause to be proven, and also
|
||||
/// identifies the index of the predicate in the `predicates_of`
|
||||
|
@ -1011,25 +1011,41 @@ fn ty_and_layout_pointee_info_at(
|
||||
}
|
||||
|
||||
_ => {
|
||||
let mut data_variant = match this.variants {
|
||||
let mut data_variant = match &this.variants {
|
||||
// Within the discriminant field, only the niche itself is
|
||||
// always initialized, so we only check for a pointer at its
|
||||
// offset.
|
||||
//
|
||||
// If the niche is a pointer, it's either valid (according
|
||||
// to its type), or null (which the niche field's scalar
|
||||
// validity range encodes). This allows using
|
||||
// `dereferenceable_or_null` for e.g., `Option<&T>`, and
|
||||
// this will continue to work as long as we don't start
|
||||
// using more niches than just null (e.g., the first page of
|
||||
// the address space, or unaligned pointers).
|
||||
// Our goal here is to check whether this represents a
|
||||
// "dereferenceable or null" pointer, so we need to ensure
|
||||
// that there is only one other variant, and it must be null.
|
||||
// Below, we will then check whether the pointer is indeed
|
||||
// dereferenceable.
|
||||
Variants::Multiple {
|
||||
tag_encoding: TagEncoding::Niche { untagged_variant, .. },
|
||||
tag_encoding:
|
||||
TagEncoding::Niche { untagged_variant, niche_variants, niche_start },
|
||||
tag_field,
|
||||
variants,
|
||||
..
|
||||
} if this.fields.offset(tag_field) == offset => {
|
||||
Some(this.for_variant(cx, untagged_variant))
|
||||
} if variants.len() == 2 && this.fields.offset(*tag_field) == offset => {
|
||||
let tagged_variant = if untagged_variant.as_u32() == 0 {
|
||||
VariantIdx::from_u32(1)
|
||||
} else {
|
||||
VariantIdx::from_u32(0)
|
||||
};
|
||||
assert_eq!(tagged_variant, *niche_variants.start());
|
||||
if *niche_start == 0 {
|
||||
// The other variant is encoded as "null", so we can recurse searching for
|
||||
// a pointer here. This relies on the fact that the codegen backend
|
||||
// only adds "dereferenceable" if there's also a "nonnull" proof,
|
||||
// and that null is aligned for all alignments so it's okay to forward
|
||||
// the pointer's alignment.
|
||||
Some(this.for_variant(cx, *untagged_variant))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Variants::Multiple { .. } => None,
|
||||
_ => Some(this),
|
||||
};
|
||||
|
||||
|
@ -1076,11 +1076,6 @@ pub fn new(caller_bounds: Clauses<'tcx>, reveal: Reveal) -> Self {
|
||||
ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, ParamTag { reveal }) }
|
||||
}
|
||||
|
||||
pub fn with_user_facing(mut self) -> Self {
|
||||
self.packed.set_tag(ParamTag { reveal: Reveal::UserFacing, ..self.packed.tag() });
|
||||
self
|
||||
}
|
||||
|
||||
/// Returns a new parameter environment with the same clauses, but
|
||||
/// which "reveals" the true results of projections in all cases
|
||||
/// (even for associated types that are specializable). This is
|
||||
@ -1095,6 +1090,12 @@ pub fn with_reveal_all_normalized(self, tcx: TyCtxt<'tcx>) -> Self {
|
||||
return self;
|
||||
}
|
||||
|
||||
// No need to reveal opaques with the new solver enabled,
|
||||
// since we have lazy norm.
|
||||
if tcx.next_trait_solver_globally() {
|
||||
return ParamEnv::new(self.caller_bounds(), Reveal::All);
|
||||
}
|
||||
|
||||
ParamEnv::new(tcx.reveal_opaque_types_in_bounds(self.caller_bounds()), Reveal::All)
|
||||
}
|
||||
|
||||
|
@ -1933,6 +1933,7 @@ pub fn primitive_symbol(self) -> Option<Symbol> {
|
||||
ty::UintTy::U64 => Some(sym::u64),
|
||||
ty::UintTy::U128 => Some(sym::u128),
|
||||
},
|
||||
ty::Str => Some(sym::str),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -1751,6 +1751,7 @@ pub fn reveal_opaque_types_in_bounds<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
val: ty::Clauses<'tcx>,
|
||||
) -> ty::Clauses<'tcx> {
|
||||
assert!(!tcx.next_trait_solver_globally());
|
||||
let mut visitor = OpaqueTypeExpander {
|
||||
seen_opaque_tys: FxHashSet::default(),
|
||||
expanded_cache: FxHashMap::default(),
|
||||
|
@ -77,6 +77,8 @@ parse_box_syntax_removed_suggestion = use `Box::new()` instead
|
||||
|
||||
parse_cannot_be_raw_ident = `{$ident}` cannot be a raw identifier
|
||||
|
||||
parse_cannot_be_raw_lifetime = `{$ident}` cannot be a raw lifetime
|
||||
|
||||
parse_catch_after_try = keyword `catch` cannot follow a `try` block
|
||||
.help = try using `match` on the result of the `try` block instead
|
||||
|
||||
|
@ -2018,6 +2018,14 @@ pub(crate) struct CannotBeRawIdent {
|
||||
pub ident: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_cannot_be_raw_lifetime)]
|
||||
pub(crate) struct CannotBeRawLifetime {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub ident: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_keyword_lifetime)]
|
||||
pub(crate) struct KeywordLifetime {
|
||||
|
@ -294,15 +294,21 @@ fn next_token(&mut self) -> (Token, bool) {
|
||||
let prefix_span = self.mk_sp(start, ident_start);
|
||||
|
||||
if prefix_span.at_least_rust_2021() {
|
||||
let lifetime_name_without_tick = self.str_from(ident_start);
|
||||
let span = self.mk_sp(start, self.pos);
|
||||
|
||||
let lifetime_name_without_tick = Symbol::intern(&self.str_from(ident_start));
|
||||
if !lifetime_name_without_tick.can_be_raw() {
|
||||
self.dcx().emit_err(errors::CannotBeRawLifetime { span, ident: lifetime_name_without_tick });
|
||||
}
|
||||
|
||||
// Put the `'` back onto the lifetime name.
|
||||
let mut lifetime_name = String::with_capacity(lifetime_name_without_tick.len() + 1);
|
||||
let mut lifetime_name = String::with_capacity(lifetime_name_without_tick.as_str().len() + 1);
|
||||
lifetime_name.push('\'');
|
||||
lifetime_name += lifetime_name_without_tick;
|
||||
lifetime_name += lifetime_name_without_tick.as_str();
|
||||
let sym = Symbol::intern(&lifetime_name);
|
||||
|
||||
// Make sure we mark this as a raw identifier.
|
||||
self.psess.raw_identifier_spans.push(self.mk_sp(start, self.pos));
|
||||
self.psess.raw_identifier_spans.push(span);
|
||||
|
||||
token::Lifetime(sym, IdentIsRaw::Yes)
|
||||
} else {
|
||||
|
@ -1472,7 +1472,7 @@ fn smart_resolve_context_dependent_help(
|
||||
};
|
||||
|
||||
if lhs_span.eq_ctxt(rhs_span) {
|
||||
err.span_suggestion(
|
||||
err.span_suggestion_verbose(
|
||||
lhs_span.between(rhs_span),
|
||||
MESSAGE,
|
||||
"::",
|
||||
|
@ -12,7 +12,7 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::{self, FromStr};
|
||||
use std::sync::LazyLock;
|
||||
use std::{fmt, fs, iter};
|
||||
use std::{cmp, fmt, fs, iter};
|
||||
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
|
||||
use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey};
|
||||
@ -1367,13 +1367,38 @@ pub fn build_target_config(early_dcx: &EarlyDiagCtxt, opts: &Options, sysroot: &
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
enum OptionStability {
|
||||
pub enum OptionStability {
|
||||
Stable,
|
||||
Unstable,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub enum OptionKind {
|
||||
/// An option that takes a value, and cannot appear more than once (e.g. `--out-dir`).
|
||||
///
|
||||
/// Corresponds to [`getopts::Options::optopt`].
|
||||
Opt,
|
||||
|
||||
/// An option that takes a value, and can appear multiple times (e.g. `--emit`).
|
||||
///
|
||||
/// Corresponds to [`getopts::Options::optmulti`].
|
||||
Multi,
|
||||
|
||||
/// An option that does not take a value, and cannot appear more than once (e.g. `--help`).
|
||||
///
|
||||
/// Corresponds to [`getopts::Options::optflag`].
|
||||
/// The `hint` string must be empty.
|
||||
Flag,
|
||||
|
||||
/// An option that does not take a value, and can appear multiple times (e.g. `-O`).
|
||||
///
|
||||
/// Corresponds to [`getopts::Options::optflagmulti`].
|
||||
/// The `hint` string must be empty.
|
||||
FlagMulti,
|
||||
}
|
||||
|
||||
pub struct RustcOptGroup {
|
||||
pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
|
||||
apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
|
||||
pub name: &'static str,
|
||||
stability: OptionStability,
|
||||
}
|
||||
@ -1383,73 +1408,42 @@ pub fn is_stable(&self) -> bool {
|
||||
self.stability == OptionStability::Stable
|
||||
}
|
||||
|
||||
pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
|
||||
where
|
||||
F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
|
||||
{
|
||||
RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
|
||||
}
|
||||
|
||||
pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
|
||||
where
|
||||
F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
|
||||
{
|
||||
RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
|
||||
pub fn apply(&self, options: &mut getopts::Options) {
|
||||
(self.apply)(options);
|
||||
}
|
||||
}
|
||||
|
||||
// The `opt` local module holds wrappers around the `getopts` API that
|
||||
// adds extra rustc-specific metadata to each option; such metadata
|
||||
// is exposed by . The public
|
||||
// functions below ending with `_u` are the functions that return
|
||||
// *unstable* options, i.e., options that are only enabled when the
|
||||
// user also passes the `-Z unstable-options` debugging flag.
|
||||
mod opt {
|
||||
// The `fn flag*` etc below are written so that we can use them
|
||||
// in the future; do not warn about them not being used right now.
|
||||
#![allow(dead_code)]
|
||||
|
||||
use super::RustcOptGroup;
|
||||
|
||||
type R = RustcOptGroup;
|
||||
type S = &'static str;
|
||||
|
||||
fn stable<F>(name: S, f: F) -> R
|
||||
where
|
||||
F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
|
||||
{
|
||||
RustcOptGroup::stable(name, f)
|
||||
}
|
||||
|
||||
fn unstable<F>(name: S, f: F) -> R
|
||||
where
|
||||
F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
|
||||
{
|
||||
RustcOptGroup::unstable(name, f)
|
||||
}
|
||||
|
||||
fn longer(a: S, b: S) -> S {
|
||||
if a.len() > b.len() { a } else { b }
|
||||
}
|
||||
|
||||
pub(crate) fn opt_s(a: S, b: S, c: S, d: S) -> R {
|
||||
stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
|
||||
}
|
||||
pub(crate) fn multi_s(a: S, b: S, c: S, d: S) -> R {
|
||||
stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
|
||||
}
|
||||
pub(crate) fn flag_s(a: S, b: S, c: S) -> R {
|
||||
stable(longer(a, b), move |opts| opts.optflag(a, b, c))
|
||||
}
|
||||
pub(crate) fn flagmulti_s(a: S, b: S, c: S) -> R {
|
||||
stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
|
||||
}
|
||||
|
||||
fn opt(a: S, b: S, c: S, d: S) -> R {
|
||||
unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
|
||||
}
|
||||
pub(crate) fn multi(a: S, b: S, c: S, d: S) -> R {
|
||||
unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
|
||||
pub fn make_opt(
|
||||
stability: OptionStability,
|
||||
kind: OptionKind,
|
||||
short_name: &'static str,
|
||||
long_name: &'static str,
|
||||
desc: &'static str,
|
||||
hint: &'static str,
|
||||
) -> RustcOptGroup {
|
||||
RustcOptGroup {
|
||||
name: cmp::max_by_key(short_name, long_name, |s| s.len()),
|
||||
stability,
|
||||
apply: match kind {
|
||||
OptionKind::Opt => Box::new(move |opts: &mut getopts::Options| {
|
||||
opts.optopt(short_name, long_name, desc, hint)
|
||||
}),
|
||||
OptionKind::Multi => Box::new(move |opts: &mut getopts::Options| {
|
||||
opts.optmulti(short_name, long_name, desc, hint)
|
||||
}),
|
||||
OptionKind::Flag => {
|
||||
assert_eq!(hint, "");
|
||||
Box::new(move |opts: &mut getopts::Options| {
|
||||
opts.optflag(short_name, long_name, desc)
|
||||
})
|
||||
}
|
||||
OptionKind::FlagMulti => {
|
||||
assert_eq!(hint, "");
|
||||
Box::new(move |opts: &mut getopts::Options| {
|
||||
opts.optflagmulti(short_name, long_name, desc)
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -1464,46 +1458,60 @@ pub(crate) fn multi(a: S, b: S, c: S, d: S) -> R {
|
||||
/// including metadata for each option, such as whether the option is
|
||||
/// part of the stable long-term interface for rustc.
|
||||
pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
|
||||
use OptionKind::{Flag, FlagMulti, Multi, Opt};
|
||||
use OptionStability::Stable;
|
||||
|
||||
use self::make_opt as opt;
|
||||
|
||||
vec![
|
||||
opt::flag_s("h", "help", "Display this message"),
|
||||
opt::multi_s("", "cfg", "Configure the compilation environment.
|
||||
SPEC supports the syntax `NAME[=\"VALUE\"]`.", "SPEC"),
|
||||
opt::multi_s("", "check-cfg", "Provide list of expected cfgs for checking", "SPEC"),
|
||||
opt::multi_s(
|
||||
opt(Stable, Flag, "h", "help", "Display this message", ""),
|
||||
opt(
|
||||
Stable,
|
||||
Multi,
|
||||
"",
|
||||
"cfg",
|
||||
"Configure the compilation environment.\n\
|
||||
SPEC supports the syntax `NAME[=\"VALUE\"]`.",
|
||||
"SPEC",
|
||||
),
|
||||
opt(Stable, Multi, "", "check-cfg", "Provide list of expected cfgs for checking", "SPEC"),
|
||||
opt(
|
||||
Stable,
|
||||
Multi,
|
||||
"L",
|
||||
"",
|
||||
"Add a directory to the library search path. The
|
||||
optional KIND can be one of dependency, crate, native,
|
||||
framework, or all (the default).",
|
||||
"Add a directory to the library search path. \
|
||||
The optional KIND can be one of dependency, crate, native, framework, or all (the default).",
|
||||
"[KIND=]PATH",
|
||||
),
|
||||
opt::multi_s(
|
||||
opt(
|
||||
Stable,
|
||||
Multi,
|
||||
"l",
|
||||
"",
|
||||
"Link the generated crate(s) to the specified native
|
||||
library NAME. The optional KIND can be one of
|
||||
static, framework, or dylib (the default).
|
||||
Optional comma separated MODIFIERS (bundle|verbatim|whole-archive|as-needed)
|
||||
may be specified each with a prefix of either '+' to
|
||||
enable or '-' to disable.",
|
||||
"Link the generated crate(s) to the specified native\n\
|
||||
library NAME. The optional KIND can be one of\n\
|
||||
static, framework, or dylib (the default).\n\
|
||||
Optional comma separated MODIFIERS\n\
|
||||
(bundle|verbatim|whole-archive|as-needed)\n\
|
||||
may be specified each with a prefix of either '+' to\n\
|
||||
enable or '-' to disable.",
|
||||
"[KIND[:MODIFIERS]=]NAME[:RENAME]",
|
||||
),
|
||||
make_crate_type_option(),
|
||||
opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
|
||||
opt::opt_s(
|
||||
"",
|
||||
"edition",
|
||||
&EDITION_STRING,
|
||||
EDITION_NAME_LIST,
|
||||
),
|
||||
opt::multi_s(
|
||||
opt(Stable, Opt, "", "crate-name", "Specify the name of the crate being built", "NAME"),
|
||||
opt(Stable, Opt, "", "edition", &EDITION_STRING, EDITION_NAME_LIST),
|
||||
opt(
|
||||
Stable,
|
||||
Multi,
|
||||
"",
|
||||
"emit",
|
||||
"Comma separated list of types of output for \
|
||||
the compiler to emit",
|
||||
"Comma separated list of types of output for the compiler to emit",
|
||||
"[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
|
||||
),
|
||||
opt::multi_s(
|
||||
opt(
|
||||
Stable,
|
||||
Multi,
|
||||
"",
|
||||
"print",
|
||||
"Compiler information to print on stdout",
|
||||
@ -1512,41 +1520,36 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
|
||||
tls-models|target-spec-json|all-target-specs-json|native-static-libs|\
|
||||
stack-protector-strategies|link-args|deployment-target]",
|
||||
),
|
||||
opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
|
||||
opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
|
||||
opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
|
||||
opt::opt_s(
|
||||
"",
|
||||
"out-dir",
|
||||
"Write output to compiler-chosen filename \
|
||||
in <dir>",
|
||||
"DIR",
|
||||
),
|
||||
opt::opt_s(
|
||||
opt(Stable, FlagMulti, "g", "", "Equivalent to -C debuginfo=2", ""),
|
||||
opt(Stable, FlagMulti, "O", "", "Equivalent to -C opt-level=2", ""),
|
||||
opt(Stable, Opt, "o", "", "Write output to <filename>", "FILENAME"),
|
||||
opt(Stable, Opt, "", "out-dir", "Write output to compiler-chosen filename in <dir>", "DIR"),
|
||||
opt(
|
||||
Stable,
|
||||
Opt,
|
||||
"",
|
||||
"explain",
|
||||
"Provide a detailed explanation of an error \
|
||||
message",
|
||||
"Provide a detailed explanation of an error message",
|
||||
"OPT",
|
||||
),
|
||||
opt::flag_s("", "test", "Build a test harness"),
|
||||
opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
|
||||
opt::multi_s("A", "allow", "Set lint allowed", "LINT"),
|
||||
opt::multi_s("W", "warn", "Set lint warnings", "LINT"),
|
||||
opt::multi_s("", "force-warn", "Set lint force-warn", "LINT"),
|
||||
opt::multi_s("D", "deny", "Set lint denied", "LINT"),
|
||||
opt::multi_s("F", "forbid", "Set lint forbidden", "LINT"),
|
||||
opt::multi_s(
|
||||
opt(Stable, Flag, "", "test", "Build a test harness", ""),
|
||||
opt(Stable, Opt, "", "target", "Target triple for which the code is compiled", "TARGET"),
|
||||
opt(Stable, Multi, "A", "allow", "Set lint allowed", "LINT"),
|
||||
opt(Stable, Multi, "W", "warn", "Set lint warnings", "LINT"),
|
||||
opt(Stable, Multi, "", "force-warn", "Set lint force-warn", "LINT"),
|
||||
opt(Stable, Multi, "D", "deny", "Set lint denied", "LINT"),
|
||||
opt(Stable, Multi, "F", "forbid", "Set lint forbidden", "LINT"),
|
||||
opt(
|
||||
Stable,
|
||||
Multi,
|
||||
"",
|
||||
"cap-lints",
|
||||
"Set the most restrictive lint level. \
|
||||
More restrictive lints are capped at this \
|
||||
level",
|
||||
"Set the most restrictive lint level. More restrictive lints are capped at this level",
|
||||
"LEVEL",
|
||||
),
|
||||
opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
|
||||
opt::flag_s("V", "version", "Print version info and exit"),
|
||||
opt::flag_s("v", "verbose", "Use verbose output"),
|
||||
opt(Stable, Multi, "C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
|
||||
opt(Stable, Flag, "V", "version", "Print version info and exit", ""),
|
||||
opt(Stable, Flag, "v", "verbose", "Use verbose output", ""),
|
||||
]
|
||||
}
|
||||
|
||||
@ -1554,25 +1557,36 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
|
||||
/// each option, such as whether the option is part of the stable
|
||||
/// long-term interface for rustc.
|
||||
pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
|
||||
use OptionKind::{Multi, Opt};
|
||||
use OptionStability::{Stable, Unstable};
|
||||
|
||||
use self::make_opt as opt;
|
||||
|
||||
let mut opts = rustc_short_optgroups();
|
||||
// FIXME: none of these descriptions are actually used
|
||||
opts.extend(vec![
|
||||
opt::multi_s(
|
||||
opt(
|
||||
Stable,
|
||||
Multi,
|
||||
"",
|
||||
"extern",
|
||||
"Specify where an external rust library is located",
|
||||
"NAME[=PATH]",
|
||||
),
|
||||
opt::opt_s("", "sysroot", "Override the system root", "PATH"),
|
||||
opt::multi("Z", "", "Set unstable / perma-unstable options", "FLAG"),
|
||||
opt::opt_s(
|
||||
opt(Stable, Opt, "", "sysroot", "Override the system root", "PATH"),
|
||||
opt(Unstable, Multi, "Z", "", "Set unstable / perma-unstable options", "FLAG"),
|
||||
opt(
|
||||
Stable,
|
||||
Opt,
|
||||
"",
|
||||
"error-format",
|
||||
"How errors and other messages are produced",
|
||||
"human|json|short",
|
||||
),
|
||||
opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
|
||||
opt::opt_s(
|
||||
opt(Stable, Multi, "", "json", "Configure the JSON output of the compiler", "CONFIG"),
|
||||
opt(
|
||||
Stable,
|
||||
Opt,
|
||||
"",
|
||||
"color",
|
||||
"Configure coloring of output:
|
||||
@ -1581,19 +1595,23 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
|
||||
never = never colorize output",
|
||||
"auto|always|never",
|
||||
),
|
||||
opt::opt_s(
|
||||
opt(
|
||||
Stable,
|
||||
Opt,
|
||||
"",
|
||||
"diagnostic-width",
|
||||
"Inform rustc of the width of the output so that diagnostics can be truncated to fit",
|
||||
"WIDTH",
|
||||
),
|
||||
opt::multi_s(
|
||||
opt(
|
||||
Stable,
|
||||
Multi,
|
||||
"",
|
||||
"remap-path-prefix",
|
||||
"Remap source names in all output (compiler messages and output files)",
|
||||
"FROM=TO",
|
||||
),
|
||||
opt::multi("", "env-set", "Inject an environment variable", "VAR=VALUE"),
|
||||
opt(Unstable, Multi, "", "env-set", "Inject an environment variable", "VAR=VALUE"),
|
||||
]);
|
||||
opts
|
||||
}
|
||||
@ -2756,7 +2774,9 @@ fn parse_pretty(early_dcx: &EarlyDiagCtxt, unstable_opts: &UnstableOptions) -> O
|
||||
}
|
||||
|
||||
pub fn make_crate_type_option() -> RustcOptGroup {
|
||||
opt::multi_s(
|
||||
make_opt(
|
||||
OptionStability::Stable,
|
||||
OptionKind::Multi,
|
||||
"",
|
||||
"crate-type",
|
||||
"Comma separated list of types of crates
|
||||
|
@ -155,6 +155,7 @@ pub fn feature_warn_issue(
|
||||
}
|
||||
|
||||
/// Adds the diagnostics for a feature to an existing error.
|
||||
/// Must be a language feature!
|
||||
pub fn add_feature_diagnostics<G: EmissionGuarantee>(
|
||||
err: &mut Diag<'_, G>,
|
||||
sess: &Session,
|
||||
|
@ -300,6 +300,7 @@ pub fn is_test_crate(&self) -> bool {
|
||||
self.opts.test
|
||||
}
|
||||
|
||||
/// `feature` must be a language feature.
|
||||
#[track_caller]
|
||||
pub fn create_feature_err<'a>(&'a self, err: impl Diagnostic<'a>, feature: Symbol) -> Diag<'a> {
|
||||
let mut err = self.dcx().create_err(err);
|
||||
|
@ -1867,6 +1867,7 @@
|
||||
slice_patterns,
|
||||
slicing_syntax,
|
||||
soft,
|
||||
sparc_target_feature,
|
||||
specialization,
|
||||
speed,
|
||||
spotlight,
|
||||
@ -2109,6 +2110,7 @@
|
||||
usize_legacy_fn_max_value,
|
||||
usize_legacy_fn_min_value,
|
||||
usize_legacy_mod,
|
||||
v8plus,
|
||||
va_arg,
|
||||
va_copy,
|
||||
va_end,
|
||||
|
@ -143,7 +143,8 @@ pub struct ArgAttributes {
|
||||
pub regular: ArgAttribute,
|
||||
pub arg_ext: ArgExtension,
|
||||
/// The minimum size of the pointee, guaranteed to be valid for the duration of the whole call
|
||||
/// (corresponding to LLVM's dereferenceable and dereferenceable_or_null attributes).
|
||||
/// (corresponding to LLVM's dereferenceable_or_null attributes, i.e., it is okay for this to be
|
||||
/// set on a null pointer, but all non-null pointers must be dereferenceable).
|
||||
pub pointee_size: Size,
|
||||
pub pointee_align: Option<Align>,
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ pub(crate) fn target() -> Target {
|
||||
std: Some(true),
|
||||
},
|
||||
pointer_width: 64,
|
||||
data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
|
||||
data_layout: "E-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
|
||||
arch: "aarch64".into(),
|
||||
options: TargetOptions {
|
||||
features: "+v8a,+outline-atomics".into(),
|
||||
|
@ -14,7 +14,7 @@ pub(crate) fn target() -> Target {
|
||||
std: Some(true),
|
||||
},
|
||||
pointer_width: 32,
|
||||
data_layout: "E-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
|
||||
data_layout: "E-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
|
||||
arch: "aarch64".into(),
|
||||
options: TargetOptions {
|
||||
abi: "ilp32".into(),
|
||||
|
@ -11,7 +11,7 @@ pub(crate) fn target() -> Target {
|
||||
std: Some(true),
|
||||
},
|
||||
pointer_width: 64,
|
||||
data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
|
||||
data_layout: "E-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
|
||||
arch: "aarch64".into(),
|
||||
options: TargetOptions {
|
||||
mcount: "__mcount".into(),
|
||||
|
@ -10,7 +10,7 @@ pub(crate) fn target() -> Target {
|
||||
std: Some(true),
|
||||
},
|
||||
pointer_width: 32,
|
||||
data_layout: "e-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
|
||||
data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
|
||||
arch: "aarch64".into(),
|
||||
options: TargetOptions {
|
||||
abi: "ilp32".into(),
|
||||
|
@ -14,6 +14,7 @@ pub(crate) fn target() -> Target {
|
||||
data_layout: "E-m:e-p:32:32-i64:64-i128:128-f128:64-n32-S64".into(),
|
||||
arch: "sparc".into(),
|
||||
options: TargetOptions {
|
||||
features: "+v8plus".into(),
|
||||
cpu: "v9".into(),
|
||||
endian: Endian::Big,
|
||||
late_link_args: TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &[
|
||||
|
@ -545,6 +545,14 @@ pub fn is_supported(self) -> bool {
|
||||
// tidy-alphabetical-end
|
||||
];
|
||||
|
||||
const SPARC_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
// tidy-alphabetical-start
|
||||
("leoncasa", Unstable(sym::sparc_target_feature), &[]),
|
||||
("v8plus", Unstable(sym::sparc_target_feature), &[]),
|
||||
("v9", Unstable(sym::sparc_target_feature), &[]),
|
||||
// tidy-alphabetical-end
|
||||
];
|
||||
|
||||
/// When rustdoc is running, provide a list of all known features so that all their respective
|
||||
/// primitives may be documented.
|
||||
///
|
||||
@ -563,6 +571,7 @@ pub fn all_rust_features() -> impl Iterator<Item = (&'static str, Stability)> {
|
||||
.chain(CSKY_FEATURES)
|
||||
.chain(LOONGARCH_FEATURES)
|
||||
.chain(IBMZ_FEATURES)
|
||||
.chain(SPARC_FEATURES)
|
||||
.cloned()
|
||||
.map(|(f, s, _)| (f, s))
|
||||
}
|
||||
@ -589,6 +598,7 @@ pub fn rust_target_features(&self) -> &'static [(&'static str, Stability, Implie
|
||||
"csky" => CSKY_FEATURES,
|
||||
"loongarch64" => LOONGARCH_FEATURES,
|
||||
"s390x" => IBMZ_FEATURES,
|
||||
"sparc" | "sparc64" => SPARC_FEATURES,
|
||||
_ => &[],
|
||||
}
|
||||
}
|
||||
|
@ -2953,6 +2953,22 @@ pub(super) fn note_obligation_cause_code<G: EmissionGuarantee, T>(
|
||||
// We hold the `DefId` of the item introducing the obligation, but displaying it
|
||||
// doesn't add user usable information. It always point at an associated item.
|
||||
}
|
||||
ObligationCauseCode::OpaqueTypeBound(span, definition_def_id) => {
|
||||
err.span_note(span, "required by a bound in an opaque type");
|
||||
if let Some(definition_def_id) = definition_def_id
|
||||
// If there are any stalled coroutine obligations, then this
|
||||
// error may be due to that, and not because the body has more
|
||||
// where-clauses.
|
||||
&& self.tcx.typeck(definition_def_id).coroutine_stalled_predicates.is_empty()
|
||||
{
|
||||
// FIXME(compiler-errors): We could probably point to something
|
||||
// specific here if we tried hard enough...
|
||||
err.span_note(
|
||||
tcx.def_span(definition_def_id),
|
||||
"this definition site has more where clauses than the opaque type",
|
||||
);
|
||||
}
|
||||
}
|
||||
ObligationCauseCode::Coercion { source, target } => {
|
||||
let source =
|
||||
tcx.short_ty_string(self.resolve_vars_if_possible(source), long_ty_file);
|
||||
|
@ -818,10 +818,12 @@ pub fn get_mut(&mut self) -> Option<&mut (dyn error::Error + Send + Sync + 'stat
|
||||
|
||||
/// Consumes the `Error`, returning its inner error (if any).
|
||||
///
|
||||
/// If this [`Error`] was constructed via [`new`] then this function will
|
||||
/// return [`Some`], otherwise it will return [`None`].
|
||||
/// If this [`Error`] was constructed via [`new`] or [`other`],
|
||||
/// then this function will return [`Some`],
|
||||
/// otherwise it will return [`None`].
|
||||
///
|
||||
/// [`new`]: Error::new
|
||||
/// [`other`]: Error::other
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -11,6 +11,7 @@ extended = true
|
||||
# Most users installing from source want to build all parts of the project from source.
|
||||
[llvm]
|
||||
download-ci-llvm = false
|
||||
|
||||
[rust]
|
||||
# We have several defaults in bootstrap that depend on whether the channel is `dev` (e.g. `omit-git-hash` and `download-ci-llvm`).
|
||||
# Make sure they don't get set when installing from source.
|
||||
|
@ -8,9 +8,6 @@ bench-stage = 0
|
||||
[rust]
|
||||
# This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower.
|
||||
incremental = true
|
||||
# Download rustc from CI instead of building it from source.
|
||||
# For stage > 1 builds, this cuts compile times significantly when there are no changes on "compiler" tree.
|
||||
download-rustc = "if-unchanged"
|
||||
# Make the compiler and standard library faster to build, at the expense of a ~20% runtime slowdown.
|
||||
lto = "off"
|
||||
|
||||
|
@ -3,11 +3,6 @@
|
||||
[rust]
|
||||
# This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower.
|
||||
incremental = true
|
||||
# Download rustc from CI instead of building it from source.
|
||||
# For stage > 1 builds, this cuts compile times significantly when there are no changes on "compiler" tree.
|
||||
# Using these defaults will download the stage2 compiler (see `download-rustc`
|
||||
# setting) and the stage2 toolchain should therefore be used for these defaults.
|
||||
download-rustc = "if-unchanged"
|
||||
|
||||
[build]
|
||||
# Document with the in-tree rustdoc by default, since `download-rustc` makes it quick to compile.
|
||||
|
@ -1665,10 +1665,26 @@ fn get_table(option: &str) -> Result<TomlConfig, toml::de::Error> {
|
||||
let mut debuginfo_level_tools = None;
|
||||
let mut debuginfo_level_tests = None;
|
||||
let mut optimize = None;
|
||||
let mut omit_git_hash = None;
|
||||
let mut lld_enabled = None;
|
||||
let mut std_features = None;
|
||||
|
||||
let default = config.channel == "dev";
|
||||
config.omit_git_hash = toml.rust.as_ref().and_then(|r| r.omit_git_hash).unwrap_or(default);
|
||||
|
||||
config.rust_info = GitInfo::new(config.omit_git_hash, &config.src);
|
||||
config.cargo_info = GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/cargo"));
|
||||
config.rust_analyzer_info =
|
||||
GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/rust-analyzer"));
|
||||
config.clippy_info =
|
||||
GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/clippy"));
|
||||
config.miri_info = GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/miri"));
|
||||
config.rustfmt_info =
|
||||
GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/rustfmt"));
|
||||
config.enzyme_info =
|
||||
GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/enzyme"));
|
||||
config.in_tree_llvm_info = GitInfo::new(false, &config.src.join("src/llvm-project"));
|
||||
config.in_tree_gcc_info = GitInfo::new(false, &config.src.join("src/gcc"));
|
||||
|
||||
let mut is_user_configured_rust_channel = false;
|
||||
|
||||
if let Some(rust) = toml.rust {
|
||||
@ -1699,7 +1715,7 @@ fn get_table(option: &str) -> Result<TomlConfig, toml::de::Error> {
|
||||
verbose_tests,
|
||||
optimize_tests,
|
||||
codegen_tests,
|
||||
omit_git_hash: omit_git_hash_toml,
|
||||
omit_git_hash: _, // already handled above
|
||||
dist_src,
|
||||
save_toolstates,
|
||||
codegen_backends,
|
||||
@ -1750,7 +1766,6 @@ fn get_table(option: &str) -> Result<TomlConfig, toml::de::Error> {
|
||||
std_features = std_features_toml;
|
||||
|
||||
optimize = optimize_toml;
|
||||
omit_git_hash = omit_git_hash_toml;
|
||||
config.rust_new_symbol_mangling = new_symbol_mangling;
|
||||
set(&mut config.rust_optimize_tests, optimize_tests);
|
||||
set(&mut config.codegen_tests, codegen_tests);
|
||||
@ -1826,24 +1841,6 @@ fn get_table(option: &str) -> Result<TomlConfig, toml::de::Error> {
|
||||
|
||||
config.reproducible_artifacts = flags.reproducible_artifact;
|
||||
|
||||
// rust_info must be set before is_ci_llvm_available() is called.
|
||||
let default = config.channel == "dev";
|
||||
config.omit_git_hash = omit_git_hash.unwrap_or(default);
|
||||
config.rust_info = GitInfo::new(config.omit_git_hash, &config.src);
|
||||
|
||||
config.cargo_info = GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/cargo"));
|
||||
config.rust_analyzer_info =
|
||||
GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/rust-analyzer"));
|
||||
config.clippy_info =
|
||||
GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/clippy"));
|
||||
config.miri_info = GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/miri"));
|
||||
config.rustfmt_info =
|
||||
GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/rustfmt"));
|
||||
config.enzyme_info =
|
||||
GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/enzyme"));
|
||||
config.in_tree_llvm_info = GitInfo::new(false, &config.src.join("src/llvm-project"));
|
||||
config.in_tree_gcc_info = GitInfo::new(false, &config.src.join("src/gcc"));
|
||||
|
||||
// We need to override `rust.channel` if it's manually specified when using the CI rustc.
|
||||
// This is because if the compiler uses a different channel than the one specified in config.toml,
|
||||
// tests may fail due to using a different channel than the one used by the compiler during tests.
|
||||
@ -2760,9 +2757,19 @@ fn download_ci_rustc_commit(
|
||||
|
||||
// If `download-rustc` is not set, default to rebuilding.
|
||||
let if_unchanged = match download_rustc {
|
||||
None | Some(StringOrBool::Bool(false)) => return None,
|
||||
None => self.rust_info.is_managed_git_subrepository(),
|
||||
Some(StringOrBool::Bool(false)) => return None,
|
||||
Some(StringOrBool::Bool(true)) => false,
|
||||
Some(StringOrBool::String(s)) if s == "if-unchanged" => true,
|
||||
Some(StringOrBool::String(s)) if s == "if-unchanged" => {
|
||||
if !self.rust_info.is_managed_git_subrepository() {
|
||||
println!(
|
||||
"ERROR: `download-rustc=if-unchanged` is only compatible with Git managed sources."
|
||||
);
|
||||
crate::exit!(1);
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
Some(StringOrBool::String(other)) => {
|
||||
panic!("unrecognized option for download-rustc: {other}")
|
||||
}
|
||||
@ -2789,7 +2796,7 @@ fn download_ci_rustc_commit(
|
||||
}
|
||||
println!("ERROR: could not find commit hash for downloading rustc");
|
||||
println!("HELP: maybe your repository history is too shallow?");
|
||||
println!("HELP: consider disabling `download-rustc`");
|
||||
println!("HELP: consider setting `rust.download-rustc=false` in config.toml");
|
||||
println!("HELP: or fetch enough history to include one upstream commit");
|
||||
crate::exit!(1);
|
||||
}
|
||||
|
@ -135,6 +135,7 @@ fn override_toml() {
|
||||
[rust]
|
||||
lto = "off"
|
||||
deny-warnings = true
|
||||
download-rustc=false
|
||||
|
||||
[build]
|
||||
gdb = "foo"
|
||||
@ -200,6 +201,8 @@ fn override_toml() {
|
||||
.collect(),
|
||||
"setting dictionary value"
|
||||
);
|
||||
assert!(!config.llvm_from_ci);
|
||||
assert!(!config.download_rustc());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -18,7 +18,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
|
||||
- MSP430
|
||||
- M68k
|
||||
- CSKY
|
||||
- s390x
|
||||
- Arm64EC
|
||||
- SPARC
|
||||
|
||||
@ -52,11 +51,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
|
||||
| M68k | `reg_addr` | `a[0-3]` | `a` |
|
||||
| CSKY | `reg` | `r[0-31]` | `r` |
|
||||
| CSKY | `freg` | `f[0-31]` | `f` |
|
||||
| s390x | `reg` | `r[0-10]`, `r[12-14]` | `r` |
|
||||
| s390x | `reg_addr` | `r[1-10]`, `r[12-14]` | `a` |
|
||||
| s390x | `freg` | `f[0-15]` | `f` |
|
||||
| s390x | `vreg` | `v[0-31]` | Only clobbers |
|
||||
| s390x | `areg` | `a[2-15]` | Only clobbers |
|
||||
| SPARC | `reg` | `r[2-29]` | `r` |
|
||||
| SPARC | `yreg` | `y` | Only clobbers |
|
||||
| Arm64EC | `reg` | `x[0-12]`, `x[15-22]`, `x[25-27]`, `x30` | `r` |
|
||||
@ -96,10 +90,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
|
||||
| M68k | `reg_data` | None | `i8`, `i16`, `i32` |
|
||||
| CSKY | `reg` | None | `i8`, `i16`, `i32` |
|
||||
| CSKY | `freg` | None | `f32`, |
|
||||
| s390x | `reg`, `reg_addr` | None | `i8`, `i16`, `i32`, `i64` |
|
||||
| s390x | `freg` | None | `f32`, `f64` |
|
||||
| s390x | `vreg` | N/A | Only clobbers |
|
||||
| s390x | `areg` | N/A | Only clobbers |
|
||||
| SPARC | `reg` | None | `i8`, `i16`, `i32`, `i64` (SPARC64 only) |
|
||||
| SPARC | `yreg` | N/A | Only clobbers |
|
||||
| Arm64EC | `reg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |
|
||||
@ -159,8 +149,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
|
||||
|
||||
| Architecture | Unsupported register | Reason |
|
||||
| ------------ | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| All | `sp`, `r15` (s390x), `r14`/`o6` (SPARC) | The stack pointer must be restored to its original value at the end of an asm code block. |
|
||||
| All | `fr` (Hexagon), `fp` (PowerPC), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k), `r11` (s390x), `r30`/`i6` (SPARC), `x29` (Arm64EC) | The frame pointer cannot be used as an input or output. |
|
||||
| All | `sp`, `r14`/`o6` (SPARC) | The stack pointer must be restored to its original value at the end of an asm code block. |
|
||||
| All | `fr` (Hexagon), `fp` (PowerPC), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k), `r30`/`i6` (SPARC), `x29` (Arm64EC) | The frame pointer cannot be used as an input or output. |
|
||||
| All | `r19` (Hexagon), `r29` (PowerPC), `r30` (PowerPC), `x19` (Arm64EC) | These are used internally by LLVM as "base pointer" for functions with complex stack frames. |
|
||||
| MIPS | `$0` or `$zero` | This is a constant zero register which can't be modified. |
|
||||
| MIPS | `$1` or `$at` | Reserved for assembler. |
|
||||
@ -181,8 +171,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
|
||||
| CSKY | `r15` | This is the link register. |
|
||||
| CSKY | `r[26-30]` | Reserved by its ABI. |
|
||||
| CSKY | `r31` | This is the TLS register. |
|
||||
| s390x | `c[0-15]` | Reserved by the kernel. |
|
||||
| s390x | `a[0-1]` | Reserved for system use. |
|
||||
| SPARC | `r0`/`g0` | This is always zero and cannot be used as inputs or outputs. |
|
||||
| SPARC | `r1`/`g1` | Used internally by LLVM. |
|
||||
| SPARC | `r5`/`g5` | Reserved for system. (SPARC32 only) |
|
||||
@ -206,9 +194,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
|
||||
| PowerPC | `reg` | None | `0` | None |
|
||||
| PowerPC | `reg_nonzero` | None | `3` | None |
|
||||
| PowerPC | `freg` | None | `0` | None |
|
||||
| s390x | `reg` | None | `%r0` | None |
|
||||
| s390x | `reg_addr` | None | `%r1` | None |
|
||||
| s390x | `freg` | None | `%f0` | None |
|
||||
| SPARC | `reg` | None | `%o0` | None |
|
||||
| CSKY | `reg` | None | `r0` | None |
|
||||
| CSKY | `freg` | None | `f0` | None |
|
||||
@ -232,8 +217,6 @@ These flags registers must be restored upon exiting the asm block if the `preser
|
||||
- The status register `r2`.
|
||||
- M68k
|
||||
- The condition code register `ccr`.
|
||||
- s390x
|
||||
- The condition code register `cc`.
|
||||
- SPARC
|
||||
- Integer condition codes (`icc` and `xcc`)
|
||||
- Floating-point condition codes (`fcc[0-3]`)
|
||||
|
@ -1,3 +1,12 @@
|
||||
# This config uses a separate build directory for rust-analyzer,
|
||||
# so that r-a's checks don't block user `x` commands and vice-verse.
|
||||
# R-a's build directory is located in `build/rust-analyzer`.
|
||||
#
|
||||
# To build rustfmt and proc macro server for r-a run the following command:
|
||||
# ```
|
||||
# x b proc-macro-srv-cli rustfmt --stage 0 --build-dir build/rust-analyzer
|
||||
# ```
|
||||
|
||||
[language-server.rust-analyzer.config]
|
||||
linkedProjects = [
|
||||
"Cargo.toml",
|
||||
@ -17,16 +26,18 @@ overrideCommand = [
|
||||
"x.py",
|
||||
"check",
|
||||
"--json-output",
|
||||
"--build-dir",
|
||||
"build/rust-analyzer",
|
||||
]
|
||||
|
||||
[language-server.rust-analyzer.config.rustfmt]
|
||||
overrideCommand = [
|
||||
"build-rust-analyzer/host/rustfmt/bin/rustfmt",
|
||||
"build/rust-analyzer/host/rustfmt/bin/rustfmt",
|
||||
"--edition=2021"
|
||||
]
|
||||
|
||||
[language-server.rust-analyzer.config.procMacro]
|
||||
server = "build-rust-analyzer/host/stage0/libexec/rust-analyzer-proc-macro-srv"
|
||||
server = "build/rust-analyzer/host/stage0/libexec/rust-analyzer-proc-macro-srv"
|
||||
enable = true
|
||||
|
||||
[language-server.rust-analyzer.config.rustc]
|
||||
@ -47,4 +58,6 @@ overrideCommand = [
|
||||
"x.py",
|
||||
"check",
|
||||
"--json-output",
|
||||
"--build-dir",
|
||||
"build/rust-analyzer",
|
||||
]
|
||||
|
@ -215,477 +215,482 @@ fn init_logging(early_dcx: &EarlyDiagCtxt) {
|
||||
}
|
||||
|
||||
fn opts() -> Vec<RustcOptGroup> {
|
||||
let stable: fn(_, fn(&mut getopts::Options) -> &mut _) -> _ = RustcOptGroup::stable;
|
||||
let unstable: fn(_, fn(&mut getopts::Options) -> &mut _) -> _ = RustcOptGroup::unstable;
|
||||
use rustc_session::config::OptionKind::{Flag, FlagMulti, Multi, Opt};
|
||||
use rustc_session::config::OptionStability::{Stable, Unstable};
|
||||
use rustc_session::config::make_opt as opt;
|
||||
|
||||
vec![
|
||||
stable("h", |o| o.optflagmulti("h", "help", "show this help message")),
|
||||
stable("V", |o| o.optflagmulti("V", "version", "print rustdoc's version")),
|
||||
stable("v", |o| o.optflagmulti("v", "verbose", "use verbose output")),
|
||||
stable("w", |o| o.optopt("w", "output-format", "the output type to write", "[html]")),
|
||||
stable("output", |o| {
|
||||
o.optopt(
|
||||
"",
|
||||
"output",
|
||||
"Which directory to place the output. \
|
||||
This option is deprecated, use --out-dir instead.",
|
||||
"PATH",
|
||||
)
|
||||
}),
|
||||
stable("o", |o| o.optopt("o", "out-dir", "which directory to place the output", "PATH")),
|
||||
stable("crate-name", |o| {
|
||||
o.optopt("", "crate-name", "specify the name of this crate", "NAME")
|
||||
}),
|
||||
opt(Stable, FlagMulti, "h", "help", "show this help message", ""),
|
||||
opt(Stable, FlagMulti, "V", "version", "print rustdoc's version", ""),
|
||||
opt(Stable, FlagMulti, "v", "verbose", "use verbose output", ""),
|
||||
opt(Stable, Opt, "w", "output-format", "the output type to write", "[html]"),
|
||||
opt(
|
||||
Stable,
|
||||
Opt,
|
||||
"",
|
||||
"output",
|
||||
"Which directory to place the output. This option is deprecated, use --out-dir instead.",
|
||||
"PATH",
|
||||
),
|
||||
opt(Stable, Opt, "o", "out-dir", "which directory to place the output", "PATH"),
|
||||
opt(Stable, Opt, "", "crate-name", "specify the name of this crate", "NAME"),
|
||||
make_crate_type_option(),
|
||||
stable("L", |o| {
|
||||
o.optmulti("L", "library-path", "directory to add to crate search path", "DIR")
|
||||
}),
|
||||
stable("cfg", |o| o.optmulti("", "cfg", "pass a --cfg to rustc", "")),
|
||||
stable("check-cfg", |o| o.optmulti("", "check-cfg", "pass a --check-cfg to rustc", "")),
|
||||
stable("extern", |o| o.optmulti("", "extern", "pass an --extern to rustc", "NAME[=PATH]")),
|
||||
unstable("extern-html-root-url", |o| {
|
||||
o.optmulti(
|
||||
"",
|
||||
"extern-html-root-url",
|
||||
"base URL to use for dependencies; for example, \
|
||||
\"std=/doc\" links std::vec::Vec to /doc/std/vec/struct.Vec.html",
|
||||
"NAME=URL",
|
||||
)
|
||||
}),
|
||||
unstable("extern-html-root-takes-precedence", |o| {
|
||||
o.optflagmulti(
|
||||
"",
|
||||
"extern-html-root-takes-precedence",
|
||||
"give precedence to `--extern-html-root-url`, not `html_root_url`",
|
||||
)
|
||||
}),
|
||||
stable("C", |o| {
|
||||
o.optmulti("C", "codegen", "pass a codegen option to rustc", "OPT[=VALUE]")
|
||||
}),
|
||||
stable("document-private-items", |o| {
|
||||
o.optflagmulti("", "document-private-items", "document private items")
|
||||
}),
|
||||
unstable("document-hidden-items", |o| {
|
||||
o.optflagmulti("", "document-hidden-items", "document items that have doc(hidden)")
|
||||
}),
|
||||
stable("test", |o| o.optflagmulti("", "test", "run code examples as tests")),
|
||||
stable("test-args", |o| {
|
||||
o.optmulti("", "test-args", "arguments to pass to the test runner", "ARGS")
|
||||
}),
|
||||
stable("test-run-directory", |o| {
|
||||
o.optopt(
|
||||
"",
|
||||
"test-run-directory",
|
||||
"The working directory in which to run tests",
|
||||
"PATH",
|
||||
)
|
||||
}),
|
||||
stable("target", |o| o.optopt("", "target", "target triple to document", "TRIPLE")),
|
||||
stable("markdown-css", |o| {
|
||||
o.optmulti(
|
||||
"",
|
||||
"markdown-css",
|
||||
"CSS files to include via <link> in a rendered Markdown file",
|
||||
"FILES",
|
||||
)
|
||||
}),
|
||||
stable("html-in-header", |o| {
|
||||
o.optmulti(
|
||||
"",
|
||||
"html-in-header",
|
||||
"files to include inline in the <head> section of a rendered Markdown file \
|
||||
or generated documentation",
|
||||
"FILES",
|
||||
)
|
||||
}),
|
||||
stable("html-before-content", |o| {
|
||||
o.optmulti(
|
||||
"",
|
||||
"html-before-content",
|
||||
"files to include inline between <body> and the content of a rendered \
|
||||
Markdown file or generated documentation",
|
||||
"FILES",
|
||||
)
|
||||
}),
|
||||
stable("html-after-content", |o| {
|
||||
o.optmulti(
|
||||
"",
|
||||
"html-after-content",
|
||||
"files to include inline between the content and </body> of a rendered \
|
||||
Markdown file or generated documentation",
|
||||
"FILES",
|
||||
)
|
||||
}),
|
||||
unstable("markdown-before-content", |o| {
|
||||
o.optmulti(
|
||||
"",
|
||||
"markdown-before-content",
|
||||
"files to include inline between <body> and the content of a rendered \
|
||||
Markdown file or generated documentation",
|
||||
"FILES",
|
||||
)
|
||||
}),
|
||||
unstable("markdown-after-content", |o| {
|
||||
o.optmulti(
|
||||
"",
|
||||
"markdown-after-content",
|
||||
"files to include inline between the content and </body> of a rendered \
|
||||
Markdown file or generated documentation",
|
||||
"FILES",
|
||||
)
|
||||
}),
|
||||
stable("markdown-playground-url", |o| {
|
||||
o.optopt("", "markdown-playground-url", "URL to send code snippets to", "URL")
|
||||
}),
|
||||
stable("markdown-no-toc", |o| {
|
||||
o.optflagmulti("", "markdown-no-toc", "don't include table of contents")
|
||||
}),
|
||||
stable("e", |o| {
|
||||
o.optopt(
|
||||
"e",
|
||||
"extend-css",
|
||||
"To add some CSS rules with a given file to generate doc with your \
|
||||
own theme. However, your theme might break if the rustdoc's generated HTML \
|
||||
changes, so be careful!",
|
||||
"PATH",
|
||||
)
|
||||
}),
|
||||
unstable("Z", |o| {
|
||||
o.optmulti("Z", "", "unstable / perma-unstable options (only on nightly build)", "FLAG")
|
||||
}),
|
||||
stable("sysroot", |o| o.optopt("", "sysroot", "Override the system root", "PATH")),
|
||||
unstable("playground-url", |o| {
|
||||
o.optopt(
|
||||
"",
|
||||
"playground-url",
|
||||
"URL to send code snippets to, may be reset by --markdown-playground-url \
|
||||
or `#![doc(html_playground_url=...)]`",
|
||||
"URL",
|
||||
)
|
||||
}),
|
||||
unstable("display-doctest-warnings", |o| {
|
||||
o.optflagmulti(
|
||||
"",
|
||||
"display-doctest-warnings",
|
||||
"show warnings that originate in doctests",
|
||||
)
|
||||
}),
|
||||
stable("crate-version", |o| {
|
||||
o.optopt("", "crate-version", "crate version to print into documentation", "VERSION")
|
||||
}),
|
||||
unstable("sort-modules-by-appearance", |o| {
|
||||
o.optflagmulti(
|
||||
"",
|
||||
"sort-modules-by-appearance",
|
||||
"sort modules by where they appear in the program, rather than alphabetically",
|
||||
)
|
||||
}),
|
||||
stable("default-theme", |o| {
|
||||
o.optopt(
|
||||
"",
|
||||
"default-theme",
|
||||
"Set the default theme. THEME should be the theme name, generally lowercase. \
|
||||
If an unknown default theme is specified, the builtin default is used. \
|
||||
The set of themes, and the rustdoc built-in default, are not stable.",
|
||||
"THEME",
|
||||
)
|
||||
}),
|
||||
unstable("default-setting", |o| {
|
||||
o.optmulti(
|
||||
"",
|
||||
"default-setting",
|
||||
"Default value for a rustdoc setting (used when \"rustdoc-SETTING\" is absent \
|
||||
from web browser Local Storage). If VALUE is not supplied, \"true\" is used. \
|
||||
Supported SETTINGs and VALUEs are not documented and not stable.",
|
||||
"SETTING[=VALUE]",
|
||||
)
|
||||
}),
|
||||
stable("theme", |o| {
|
||||
o.optmulti(
|
||||
"",
|
||||
"theme",
|
||||
"additional themes which will be added to the generated docs",
|
||||
"FILES",
|
||||
)
|
||||
}),
|
||||
stable("check-theme", |o| {
|
||||
o.optmulti("", "check-theme", "check if given theme is valid", "FILES")
|
||||
}),
|
||||
unstable("resource-suffix", |o| {
|
||||
o.optopt(
|
||||
"",
|
||||
"resource-suffix",
|
||||
"suffix to add to CSS and JavaScript files, e.g., \"search-index.js\" will \
|
||||
become \"search-index-suffix.js\"",
|
||||
"PATH",
|
||||
)
|
||||
}),
|
||||
stable("edition", |o| {
|
||||
o.optopt(
|
||||
"",
|
||||
"edition",
|
||||
"edition to use when compiling rust code (default: 2015)",
|
||||
"EDITION",
|
||||
)
|
||||
}),
|
||||
stable("color", |o| {
|
||||
o.optopt(
|
||||
"",
|
||||
"color",
|
||||
"Configure coloring of output:
|
||||
opt(Stable, Multi, "L", "library-path", "directory to add to crate search path", "DIR"),
|
||||
opt(Stable, Multi, "", "cfg", "pass a --cfg to rustc", ""),
|
||||
opt(Stable, Multi, "", "check-cfg", "pass a --check-cfg to rustc", ""),
|
||||
opt(Stable, Multi, "", "extern", "pass an --extern to rustc", "NAME[=PATH]"),
|
||||
opt(
|
||||
Unstable,
|
||||
Multi,
|
||||
"",
|
||||
"extern-html-root-url",
|
||||
"base URL to use for dependencies; for example, \
|
||||
\"std=/doc\" links std::vec::Vec to /doc/std/vec/struct.Vec.html",
|
||||
"NAME=URL",
|
||||
),
|
||||
opt(
|
||||
Unstable,
|
||||
FlagMulti,
|
||||
"",
|
||||
"extern-html-root-takes-precedence",
|
||||
"give precedence to `--extern-html-root-url`, not `html_root_url`",
|
||||
"",
|
||||
),
|
||||
opt(Stable, Multi, "C", "codegen", "pass a codegen option to rustc", "OPT[=VALUE]"),
|
||||
opt(Stable, FlagMulti, "", "document-private-items", "document private items", ""),
|
||||
opt(
|
||||
Unstable,
|
||||
FlagMulti,
|
||||
"",
|
||||
"document-hidden-items",
|
||||
"document items that have doc(hidden)",
|
||||
"",
|
||||
),
|
||||
opt(Stable, FlagMulti, "", "test", "run code examples as tests", ""),
|
||||
opt(Stable, Multi, "", "test-args", "arguments to pass to the test runner", "ARGS"),
|
||||
opt(
|
||||
Stable,
|
||||
Opt,
|
||||
"",
|
||||
"test-run-directory",
|
||||
"The working directory in which to run tests",
|
||||
"PATH",
|
||||
),
|
||||
opt(Stable, Opt, "", "target", "target triple to document", "TRIPLE"),
|
||||
opt(
|
||||
Stable,
|
||||
Multi,
|
||||
"",
|
||||
"markdown-css",
|
||||
"CSS files to include via <link> in a rendered Markdown file",
|
||||
"FILES",
|
||||
),
|
||||
opt(
|
||||
Stable,
|
||||
Multi,
|
||||
"",
|
||||
"html-in-header",
|
||||
"files to include inline in the <head> section of a rendered Markdown file \
|
||||
or generated documentation",
|
||||
"FILES",
|
||||
),
|
||||
opt(
|
||||
Stable,
|
||||
Multi,
|
||||
"",
|
||||
"html-before-content",
|
||||
"files to include inline between <body> and the content of a rendered \
|
||||
Markdown file or generated documentation",
|
||||
"FILES",
|
||||
),
|
||||
opt(
|
||||
Stable,
|
||||
Multi,
|
||||
"",
|
||||
"html-after-content",
|
||||
"files to include inline between the content and </body> of a rendered \
|
||||
Markdown file or generated documentation",
|
||||
"FILES",
|
||||
),
|
||||
opt(
|
||||
Unstable,
|
||||
Multi,
|
||||
"",
|
||||
"markdown-before-content",
|
||||
"files to include inline between <body> and the content of a rendered \
|
||||
Markdown file or generated documentation",
|
||||
"FILES",
|
||||
),
|
||||
opt(
|
||||
Unstable,
|
||||
Multi,
|
||||
"",
|
||||
"markdown-after-content",
|
||||
"files to include inline between the content and </body> of a rendered \
|
||||
Markdown file or generated documentation",
|
||||
"FILES",
|
||||
),
|
||||
opt(Stable, Opt, "", "markdown-playground-url", "URL to send code snippets to", "URL"),
|
||||
opt(Stable, FlagMulti, "", "markdown-no-toc", "don't include table of contents", ""),
|
||||
opt(
|
||||
Stable,
|
||||
Opt,
|
||||
"e",
|
||||
"extend-css",
|
||||
"To add some CSS rules with a given file to generate doc with your own theme. \
|
||||
However, your theme might break if the rustdoc's generated HTML changes, so be careful!",
|
||||
"PATH",
|
||||
),
|
||||
opt(
|
||||
Unstable,
|
||||
Multi,
|
||||
"Z",
|
||||
"",
|
||||
"unstable / perma-unstable options (only on nightly build)",
|
||||
"FLAG",
|
||||
),
|
||||
opt(Stable, Opt, "", "sysroot", "Override the system root", "PATH"),
|
||||
opt(
|
||||
Unstable,
|
||||
Opt,
|
||||
"",
|
||||
"playground-url",
|
||||
"URL to send code snippets to, may be reset by --markdown-playground-url \
|
||||
or `#![doc(html_playground_url=...)]`",
|
||||
"URL",
|
||||
),
|
||||
opt(
|
||||
Unstable,
|
||||
FlagMulti,
|
||||
"",
|
||||
"display-doctest-warnings",
|
||||
"show warnings that originate in doctests",
|
||||
"",
|
||||
),
|
||||
opt(
|
||||
Stable,
|
||||
Opt,
|
||||
"",
|
||||
"crate-version",
|
||||
"crate version to print into documentation",
|
||||
"VERSION",
|
||||
),
|
||||
opt(
|
||||
Unstable,
|
||||
FlagMulti,
|
||||
"",
|
||||
"sort-modules-by-appearance",
|
||||
"sort modules by where they appear in the program, rather than alphabetically",
|
||||
"",
|
||||
),
|
||||
opt(
|
||||
Stable,
|
||||
Opt,
|
||||
"",
|
||||
"default-theme",
|
||||
"Set the default theme. THEME should be the theme name, generally lowercase. \
|
||||
If an unknown default theme is specified, the builtin default is used. \
|
||||
The set of themes, and the rustdoc built-in default, are not stable.",
|
||||
"THEME",
|
||||
),
|
||||
opt(
|
||||
Unstable,
|
||||
Multi,
|
||||
"",
|
||||
"default-setting",
|
||||
"Default value for a rustdoc setting (used when \"rustdoc-SETTING\" is absent \
|
||||
from web browser Local Storage). If VALUE is not supplied, \"true\" is used. \
|
||||
Supported SETTINGs and VALUEs are not documented and not stable.",
|
||||
"SETTING[=VALUE]",
|
||||
),
|
||||
opt(
|
||||
Stable,
|
||||
Multi,
|
||||
"",
|
||||
"theme",
|
||||
"additional themes which will be added to the generated docs",
|
||||
"FILES",
|
||||
),
|
||||
opt(Stable, Multi, "", "check-theme", "check if given theme is valid", "FILES"),
|
||||
opt(
|
||||
Unstable,
|
||||
Opt,
|
||||
"",
|
||||
"resource-suffix",
|
||||
"suffix to add to CSS and JavaScript files, \
|
||||
e.g., \"search-index.js\" will become \"search-index-suffix.js\"",
|
||||
"PATH",
|
||||
),
|
||||
opt(
|
||||
Stable,
|
||||
Opt,
|
||||
"",
|
||||
"edition",
|
||||
"edition to use when compiling rust code (default: 2015)",
|
||||
"EDITION",
|
||||
),
|
||||
opt(
|
||||
Stable,
|
||||
Opt,
|
||||
"",
|
||||
"color",
|
||||
"Configure coloring of output:
|
||||
auto = colorize, if output goes to a tty (default);
|
||||
always = always colorize output;
|
||||
never = never colorize output",
|
||||
"auto|always|never",
|
||||
)
|
||||
}),
|
||||
stable("error-format", |o| {
|
||||
o.optopt(
|
||||
"",
|
||||
"error-format",
|
||||
"How errors and other messages are produced",
|
||||
"human|json|short",
|
||||
)
|
||||
}),
|
||||
stable("diagnostic-width", |o| {
|
||||
o.optopt(
|
||||
"",
|
||||
"diagnostic-width",
|
||||
"Provide width of the output for truncated error messages",
|
||||
"WIDTH",
|
||||
)
|
||||
}),
|
||||
stable("json", |o| {
|
||||
o.optopt("", "json", "Configure the structure of JSON diagnostics", "CONFIG")
|
||||
}),
|
||||
stable("allow", |o| o.optmulti("A", "allow", "Set lint allowed", "LINT")),
|
||||
stable("warn", |o| o.optmulti("W", "warn", "Set lint warnings", "LINT")),
|
||||
stable("force-warn", |o| o.optmulti("", "force-warn", "Set lint force-warn", "LINT")),
|
||||
stable("deny", |o| o.optmulti("D", "deny", "Set lint denied", "LINT")),
|
||||
stable("forbid", |o| o.optmulti("F", "forbid", "Set lint forbidden", "LINT")),
|
||||
stable("cap-lints", |o| {
|
||||
o.optmulti(
|
||||
"",
|
||||
"cap-lints",
|
||||
"Set the most restrictive lint level. \
|
||||
More restrictive lints are capped at this \
|
||||
level. By default, it is at `forbid` level.",
|
||||
"LEVEL",
|
||||
)
|
||||
}),
|
||||
unstable("index-page", |o| {
|
||||
o.optopt("", "index-page", "Markdown file to be used as index page", "PATH")
|
||||
}),
|
||||
unstable("enable-index-page", |o| {
|
||||
o.optflagmulti("", "enable-index-page", "To enable generation of the index page")
|
||||
}),
|
||||
unstable("static-root-path", |o| {
|
||||
o.optopt(
|
||||
"",
|
||||
"static-root-path",
|
||||
"Path string to force loading static files from in output pages. \
|
||||
If not set, uses combinations of '../' to reach the documentation root.",
|
||||
"PATH",
|
||||
)
|
||||
}),
|
||||
unstable("persist-doctests", |o| {
|
||||
o.optopt(
|
||||
"",
|
||||
"persist-doctests",
|
||||
"Directory to persist doctest executables into",
|
||||
"PATH",
|
||||
)
|
||||
}),
|
||||
unstable("show-coverage", |o| {
|
||||
o.optflagmulti(
|
||||
"",
|
||||
"show-coverage",
|
||||
"calculate percentage of public items with documentation",
|
||||
)
|
||||
}),
|
||||
unstable("enable-per-target-ignores", |o| {
|
||||
o.optflagmulti(
|
||||
"",
|
||||
"enable-per-target-ignores",
|
||||
"parse ignore-foo for ignoring doctests on a per-target basis",
|
||||
)
|
||||
}),
|
||||
unstable("runtool", |o| {
|
||||
o.optopt(
|
||||
"",
|
||||
"runtool",
|
||||
"",
|
||||
"The tool to run tests with when building for a different target than host",
|
||||
)
|
||||
}),
|
||||
unstable("runtool-arg", |o| {
|
||||
o.optmulti(
|
||||
"",
|
||||
"runtool-arg",
|
||||
"",
|
||||
"One (of possibly many) arguments to pass to the runtool",
|
||||
)
|
||||
}),
|
||||
unstable("test-builder", |o| {
|
||||
o.optopt("", "test-builder", "The rustc-like binary to use as the test builder", "PATH")
|
||||
}),
|
||||
unstable("test-builder-wrapper", |o| {
|
||||
o.optmulti(
|
||||
"",
|
||||
"test-builder-wrapper",
|
||||
"Wrapper program to pass test-builder and arguments",
|
||||
"PATH",
|
||||
)
|
||||
}),
|
||||
unstable("check", |o| o.optflagmulti("", "check", "Run rustdoc checks")),
|
||||
unstable("generate-redirect-map", |o| {
|
||||
o.optflagmulti(
|
||||
"",
|
||||
"generate-redirect-map",
|
||||
"Generate JSON file at the top level instead of generating HTML redirection files",
|
||||
)
|
||||
}),
|
||||
unstable("emit", |o| {
|
||||
o.optmulti(
|
||||
"",
|
||||
"emit",
|
||||
"Comma separated list of types of output for rustdoc to emit",
|
||||
"[unversioned-shared-resources,toolchain-shared-resources,invocation-specific]",
|
||||
)
|
||||
}),
|
||||
unstable("no-run", |o| {
|
||||
o.optflagmulti("", "no-run", "Compile doctests without running them")
|
||||
}),
|
||||
unstable("remap-path-prefix", |o| {
|
||||
o.optmulti(
|
||||
"",
|
||||
"remap-path-prefix",
|
||||
"Remap source names in compiler messages",
|
||||
"FROM=TO",
|
||||
)
|
||||
}),
|
||||
unstable("show-type-layout", |o| {
|
||||
o.optflagmulti("", "show-type-layout", "Include the memory layout of types in the docs")
|
||||
}),
|
||||
unstable("nocapture", |o| {
|
||||
o.optflag("", "nocapture", "Don't capture stdout and stderr of tests")
|
||||
}),
|
||||
unstable("generate-link-to-definition", |o| {
|
||||
o.optflag(
|
||||
"",
|
||||
"generate-link-to-definition",
|
||||
"Make the identifiers in the HTML source code pages navigable",
|
||||
)
|
||||
}),
|
||||
unstable("scrape-examples-output-path", |o| {
|
||||
o.optopt(
|
||||
"",
|
||||
"scrape-examples-output-path",
|
||||
"",
|
||||
"collect function call information and output at the given path",
|
||||
)
|
||||
}),
|
||||
unstable("scrape-examples-target-crate", |o| {
|
||||
o.optmulti(
|
||||
"",
|
||||
"scrape-examples-target-crate",
|
||||
"",
|
||||
"collect function call information for functions from the target crate",
|
||||
)
|
||||
}),
|
||||
unstable("scrape-tests", |o| {
|
||||
o.optflag("", "scrape-tests", "Include test code when scraping examples")
|
||||
}),
|
||||
unstable("with-examples", |o| {
|
||||
o.optmulti(
|
||||
"",
|
||||
"with-examples",
|
||||
"",
|
||||
"path to function call information (for displaying examples in the documentation)",
|
||||
)
|
||||
}),
|
||||
unstable("merge", |o| {
|
||||
o.optopt(
|
||||
"",
|
||||
"merge",
|
||||
"Controls how rustdoc handles files from previously documented crates in the doc root
|
||||
none = Do not write cross-crate information to the --out-dir
|
||||
shared = Append current crate's info to files found in the --out-dir
|
||||
finalize = Write current crate's info and --include-parts-dir info to the --out-dir, overwriting conflicting files",
|
||||
"none|shared|finalize",
|
||||
)
|
||||
}),
|
||||
unstable("parts-out-dir", |o| {
|
||||
o.optopt(
|
||||
"",
|
||||
"parts-out-dir",
|
||||
"Writes trait implementations and other info for the current crate to provided path. Only use with --merge=none",
|
||||
"path/to/doc.parts/<crate-name>",
|
||||
)
|
||||
}),
|
||||
unstable("include-parts-dir", |o| {
|
||||
o.optmulti(
|
||||
"",
|
||||
"include-parts-dir",
|
||||
"Includes trait implementations and other crate info from provided path. Only use with --merge=finalize",
|
||||
"path/to/doc.parts/<crate-name>",
|
||||
)
|
||||
}),
|
||||
"auto|always|never",
|
||||
),
|
||||
opt(
|
||||
Stable,
|
||||
Opt,
|
||||
"",
|
||||
"error-format",
|
||||
"How errors and other messages are produced",
|
||||
"human|json|short",
|
||||
),
|
||||
opt(
|
||||
Stable,
|
||||
Opt,
|
||||
"",
|
||||
"diagnostic-width",
|
||||
"Provide width of the output for truncated error messages",
|
||||
"WIDTH",
|
||||
),
|
||||
opt(Stable, Opt, "", "json", "Configure the structure of JSON diagnostics", "CONFIG"),
|
||||
opt(Stable, Multi, "A", "allow", "Set lint allowed", "LINT"),
|
||||
opt(Stable, Multi, "W", "warn", "Set lint warnings", "LINT"),
|
||||
opt(Stable, Multi, "", "force-warn", "Set lint force-warn", "LINT"),
|
||||
opt(Stable, Multi, "D", "deny", "Set lint denied", "LINT"),
|
||||
opt(Stable, Multi, "F", "forbid", "Set lint forbidden", "LINT"),
|
||||
opt(
|
||||
Stable,
|
||||
Multi,
|
||||
"",
|
||||
"cap-lints",
|
||||
"Set the most restrictive lint level. \
|
||||
More restrictive lints are capped at this level. \
|
||||
By default, it is at `forbid` level.",
|
||||
"LEVEL",
|
||||
),
|
||||
opt(Unstable, Opt, "", "index-page", "Markdown file to be used as index page", "PATH"),
|
||||
opt(
|
||||
Unstable,
|
||||
FlagMulti,
|
||||
"",
|
||||
"enable-index-page",
|
||||
"To enable generation of the index page",
|
||||
"",
|
||||
),
|
||||
opt(
|
||||
Unstable,
|
||||
Opt,
|
||||
"",
|
||||
"static-root-path",
|
||||
"Path string to force loading static files from in output pages. \
|
||||
If not set, uses combinations of '../' to reach the documentation root.",
|
||||
"PATH",
|
||||
),
|
||||
opt(
|
||||
Unstable,
|
||||
Opt,
|
||||
"",
|
||||
"persist-doctests",
|
||||
"Directory to persist doctest executables into",
|
||||
"PATH",
|
||||
),
|
||||
opt(
|
||||
Unstable,
|
||||
FlagMulti,
|
||||
"",
|
||||
"show-coverage",
|
||||
"calculate percentage of public items with documentation",
|
||||
"",
|
||||
),
|
||||
opt(
|
||||
Unstable,
|
||||
FlagMulti,
|
||||
"",
|
||||
"enable-per-target-ignores",
|
||||
"parse ignore-foo for ignoring doctests on a per-target basis",
|
||||
"",
|
||||
),
|
||||
opt(
|
||||
Unstable,
|
||||
Opt,
|
||||
"",
|
||||
"runtool",
|
||||
"",
|
||||
"The tool to run tests with when building for a different target than host",
|
||||
),
|
||||
opt(
|
||||
Unstable,
|
||||
Multi,
|
||||
"",
|
||||
"runtool-arg",
|
||||
"",
|
||||
"One (of possibly many) arguments to pass to the runtool",
|
||||
),
|
||||
opt(
|
||||
Unstable,
|
||||
Opt,
|
||||
"",
|
||||
"test-builder",
|
||||
"The rustc-like binary to use as the test builder",
|
||||
"PATH",
|
||||
),
|
||||
opt(
|
||||
Unstable,
|
||||
Multi,
|
||||
"",
|
||||
"test-builder-wrapper",
|
||||
"Wrapper program to pass test-builder and arguments",
|
||||
"PATH",
|
||||
),
|
||||
opt(Unstable, FlagMulti, "", "check", "Run rustdoc checks", ""),
|
||||
opt(
|
||||
Unstable,
|
||||
FlagMulti,
|
||||
"",
|
||||
"generate-redirect-map",
|
||||
"Generate JSON file at the top level instead of generating HTML redirection files",
|
||||
"",
|
||||
),
|
||||
opt(
|
||||
Unstable,
|
||||
Multi,
|
||||
"",
|
||||
"emit",
|
||||
"Comma separated list of types of output for rustdoc to emit",
|
||||
"[unversioned-shared-resources,toolchain-shared-resources,invocation-specific]",
|
||||
),
|
||||
opt(Unstable, FlagMulti, "", "no-run", "Compile doctests without running them", ""),
|
||||
opt(
|
||||
Unstable,
|
||||
Multi,
|
||||
"",
|
||||
"remap-path-prefix",
|
||||
"Remap source names in compiler messages",
|
||||
"FROM=TO",
|
||||
),
|
||||
opt(
|
||||
Unstable,
|
||||
FlagMulti,
|
||||
"",
|
||||
"show-type-layout",
|
||||
"Include the memory layout of types in the docs",
|
||||
"",
|
||||
),
|
||||
opt(Unstable, Flag, "", "nocapture", "Don't capture stdout and stderr of tests", ""),
|
||||
opt(
|
||||
Unstable,
|
||||
Flag,
|
||||
"",
|
||||
"generate-link-to-definition",
|
||||
"Make the identifiers in the HTML source code pages navigable",
|
||||
"",
|
||||
),
|
||||
opt(
|
||||
Unstable,
|
||||
Opt,
|
||||
"",
|
||||
"scrape-examples-output-path",
|
||||
"",
|
||||
"collect function call information and output at the given path",
|
||||
),
|
||||
opt(
|
||||
Unstable,
|
||||
Multi,
|
||||
"",
|
||||
"scrape-examples-target-crate",
|
||||
"",
|
||||
"collect function call information for functions from the target crate",
|
||||
),
|
||||
opt(Unstable, Flag, "", "scrape-tests", "Include test code when scraping examples", ""),
|
||||
opt(
|
||||
Unstable,
|
||||
Multi,
|
||||
"",
|
||||
"with-examples",
|
||||
"",
|
||||
"path to function call information (for displaying examples in the documentation)",
|
||||
),
|
||||
opt(
|
||||
Unstable,
|
||||
Opt,
|
||||
"",
|
||||
"merge",
|
||||
"Controls how rustdoc handles files from previously documented crates in the doc root\n\
|
||||
none = Do not write cross-crate information to the --out-dir\n\
|
||||
shared = Append current crate's info to files found in the --out-dir\n\
|
||||
finalize = Write current crate's info and --include-parts-dir info to the --out-dir, overwriting conflicting files",
|
||||
"none|shared|finalize",
|
||||
),
|
||||
opt(
|
||||
Unstable,
|
||||
Opt,
|
||||
"",
|
||||
"parts-out-dir",
|
||||
"Writes trait implementations and other info for the current crate to provided path. Only use with --merge=none",
|
||||
"path/to/doc.parts/<crate-name>",
|
||||
),
|
||||
opt(
|
||||
Unstable,
|
||||
Multi,
|
||||
"",
|
||||
"include-parts-dir",
|
||||
"Includes trait implementations and other crate info from provided path. Only use with --merge=finalize",
|
||||
"path/to/doc.parts/<crate-name>",
|
||||
),
|
||||
// deprecated / removed options
|
||||
unstable("disable-minification", |o| o.optflagmulti("", "disable-minification", "removed")),
|
||||
stable("plugin-path", |o| {
|
||||
o.optmulti(
|
||||
"",
|
||||
"plugin-path",
|
||||
"removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> \
|
||||
for more information",
|
||||
"DIR",
|
||||
)
|
||||
}),
|
||||
stable("passes", |o| {
|
||||
o.optmulti(
|
||||
"",
|
||||
"passes",
|
||||
"removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> \
|
||||
for more information",
|
||||
"PASSES",
|
||||
)
|
||||
}),
|
||||
stable("plugins", |o| {
|
||||
o.optmulti(
|
||||
"",
|
||||
"plugins",
|
||||
"removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> \
|
||||
for more information",
|
||||
"PLUGINS",
|
||||
)
|
||||
}),
|
||||
stable("no-default", |o| {
|
||||
o.optflagmulti(
|
||||
"",
|
||||
"no-defaults",
|
||||
"removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> \
|
||||
for more information",
|
||||
)
|
||||
}),
|
||||
stable("r", |o| {
|
||||
o.optopt(
|
||||
"r",
|
||||
"input-format",
|
||||
"removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> \
|
||||
for more information",
|
||||
"[rust]",
|
||||
)
|
||||
}),
|
||||
unstable("html-no-source", |o| {
|
||||
o.optflag("", "html-no-source", "Disable HTML source code pages generation")
|
||||
}),
|
||||
opt(Unstable, FlagMulti, "", "disable-minification", "removed", ""),
|
||||
opt(
|
||||
Stable,
|
||||
Multi,
|
||||
"",
|
||||
"plugin-path",
|
||||
"removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
|
||||
"DIR",
|
||||
),
|
||||
opt(
|
||||
Stable,
|
||||
Multi,
|
||||
"",
|
||||
"passes",
|
||||
"removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
|
||||
"PASSES",
|
||||
),
|
||||
opt(
|
||||
Stable,
|
||||
Multi,
|
||||
"",
|
||||
"plugins",
|
||||
"removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
|
||||
"PLUGINS",
|
||||
),
|
||||
opt(
|
||||
Stable,
|
||||
FlagMulti,
|
||||
"",
|
||||
"no-defaults",
|
||||
"removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
|
||||
"",
|
||||
),
|
||||
opt(
|
||||
Stable,
|
||||
Opt,
|
||||
"r",
|
||||
"input-format",
|
||||
"removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
|
||||
"[rust]",
|
||||
),
|
||||
opt(Unstable, Flag, "", "html-no-source", "Disable HTML source code pages generation", ""),
|
||||
]
|
||||
}
|
||||
|
||||
fn usage(argv0: &str) {
|
||||
let mut options = getopts::Options::new();
|
||||
for option in opts() {
|
||||
(option.apply)(&mut options);
|
||||
option.apply(&mut options);
|
||||
}
|
||||
println!("{}", options.usage(&format!("{argv0} [options] <input>")));
|
||||
println!(" @path Read newline separated options from `path`\n");
|
||||
@ -769,7 +774,7 @@ fn main_args(
|
||||
|
||||
let mut options = getopts::Options::new();
|
||||
for option in opts() {
|
||||
(option.apply)(&mut options);
|
||||
option.apply(&mut options);
|
||||
}
|
||||
let matches = match options.parse(&args) {
|
||||
Ok(m) => m,
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 0310497822a7a673a330a5dd068b7aaa579a265e
|
||||
Subproject commit 4a2d8dc636445b276288543882e076f254b3ae95
|
@ -134,7 +134,7 @@ fn alloc_id_from_addr(&self, addr: u64, size: i64) -> Option<AllocId> {
|
||||
// entered for addresses that are not the base address, so even zero-sized
|
||||
// allocations will get recognized at their base address -- but all other
|
||||
// allocations will *not* be recognized at their "end" address.
|
||||
let size = this.get_alloc_info(alloc_id).0;
|
||||
let size = this.get_alloc_info(alloc_id).size;
|
||||
if offset < size.bytes() { Some(alloc_id) } else { None }
|
||||
}
|
||||
}?;
|
||||
@ -157,25 +157,25 @@ fn addr_from_alloc_id_uncached(
|
||||
) -> InterpResult<'tcx, u64> {
|
||||
let this = self.eval_context_ref();
|
||||
let mut rng = this.machine.rng.borrow_mut();
|
||||
let (size, align, kind) = this.get_alloc_info(alloc_id);
|
||||
let info = this.get_alloc_info(alloc_id);
|
||||
// This is either called immediately after allocation (and then cached), or when
|
||||
// adjusting `tcx` pointers (which never get freed). So assert that we are looking
|
||||
// at a live allocation. This also ensures that we never re-assign an address to an
|
||||
// allocation that previously had an address, but then was freed and the address
|
||||
// information was removed.
|
||||
assert!(!matches!(kind, AllocKind::Dead));
|
||||
assert!(!matches!(info.kind, AllocKind::Dead));
|
||||
|
||||
// This allocation does not have a base address yet, pick or reuse one.
|
||||
if this.machine.native_lib.is_some() {
|
||||
// In native lib mode, we use the "real" address of the bytes for this allocation.
|
||||
// This ensures the interpreted program and native code have the same view of memory.
|
||||
let base_ptr = match kind {
|
||||
let base_ptr = match info.kind {
|
||||
AllocKind::LiveData => {
|
||||
if this.tcx.try_get_global_alloc(alloc_id).is_some() {
|
||||
// For new global allocations, we always pre-allocate the memory to be able use the machine address directly.
|
||||
let prepared_bytes = MiriAllocBytes::zeroed(size, align)
|
||||
let prepared_bytes = MiriAllocBytes::zeroed(info.size, info.align)
|
||||
.unwrap_or_else(|| {
|
||||
panic!("Miri ran out of memory: cannot create allocation of {size:?} bytes")
|
||||
panic!("Miri ran out of memory: cannot create allocation of {size:?} bytes", size = info.size)
|
||||
});
|
||||
let ptr = prepared_bytes.as_ptr();
|
||||
// Store prepared allocation space to be picked up for use later.
|
||||
@ -203,9 +203,13 @@ fn addr_from_alloc_id_uncached(
|
||||
return interp_ok(base_ptr.expose_provenance().try_into().unwrap());
|
||||
}
|
||||
// We are not in native lib mode, so we control the addresses ourselves.
|
||||
if let Some((reuse_addr, clock)) =
|
||||
global_state.reuse.take_addr(&mut *rng, size, align, memory_kind, this.active_thread())
|
||||
{
|
||||
if let Some((reuse_addr, clock)) = global_state.reuse.take_addr(
|
||||
&mut *rng,
|
||||
info.size,
|
||||
info.align,
|
||||
memory_kind,
|
||||
this.active_thread(),
|
||||
) {
|
||||
if let Some(clock) = clock {
|
||||
this.acquire_clock(&clock);
|
||||
}
|
||||
@ -220,14 +224,14 @@ fn addr_from_alloc_id_uncached(
|
||||
.next_base_addr
|
||||
.checked_add(slack)
|
||||
.ok_or_else(|| err_exhaust!(AddressSpaceFull))?;
|
||||
let base_addr = align_addr(base_addr, align.bytes());
|
||||
let base_addr = align_addr(base_addr, info.align.bytes());
|
||||
|
||||
// Remember next base address. If this allocation is zero-sized, leave a gap of at
|
||||
// least 1 to avoid two allocations having the same base address. (The logic in
|
||||
// `alloc_id_from_addr` assumes unique addresses, and different function/vtable pointers
|
||||
// need to be distinguishable!)
|
||||
global_state.next_base_addr = base_addr
|
||||
.checked_add(max(size.bytes(), 1))
|
||||
.checked_add(max(info.size.bytes(), 1))
|
||||
.ok_or_else(|| err_exhaust!(AddressSpaceFull))?;
|
||||
// Even if `Size` didn't overflow, we might still have filled up the address space.
|
||||
if global_state.next_base_addr > this.target_usize_max() {
|
||||
|
@ -363,7 +363,7 @@ fn on_stack_pop(
|
||||
// If it does exist, then we have the guarantee that the
|
||||
// pointer is readable, and the implicit read access inserted
|
||||
// will never cause UB on the pointer itself.
|
||||
let (_, _, kind) = this.get_alloc_info(*alloc_id);
|
||||
let kind = this.get_alloc_info(*alloc_id).kind;
|
||||
if matches!(kind, AllocKind::LiveData) {
|
||||
let alloc_extra = this.get_alloc_extra(*alloc_id)?; // can still fail for `extern static`
|
||||
let alloc_borrow_tracker = &alloc_extra.borrow_tracker.as_ref().unwrap();
|
||||
|
@ -626,7 +626,7 @@ fn sb_reborrow(
|
||||
return interp_ok(())
|
||||
};
|
||||
|
||||
let (_size, _align, alloc_kind) = this.get_alloc_info(alloc_id);
|
||||
let alloc_kind = this.get_alloc_info(alloc_id).kind;
|
||||
match alloc_kind {
|
||||
AllocKind::LiveData => {
|
||||
// This should have alloc_extra data, but `get_alloc_extra` can still fail
|
||||
@ -1017,7 +1017,7 @@ fn sb_expose_tag(&mut self, alloc_id: AllocId, tag: BorTag) -> InterpResult<'tcx
|
||||
// Function pointers and dead objects don't have an alloc_extra so we ignore them.
|
||||
// This is okay because accessing them is UB anyway, no need for any Stacked Borrows checks.
|
||||
// NOT using `get_alloc_extra_mut` since this might be a read-only allocation!
|
||||
let (_size, _align, kind) = this.get_alloc_info(alloc_id);
|
||||
let kind = this.get_alloc_info(alloc_id).kind;
|
||||
match kind {
|
||||
AllocKind::LiveData => {
|
||||
// This should have alloc_extra data, but `get_alloc_extra` can still fail
|
||||
|
@ -274,7 +274,7 @@ fn tb_reborrow(
|
||||
.insert(new_tag, protect);
|
||||
}
|
||||
|
||||
let alloc_kind = this.get_alloc_info(alloc_id).2;
|
||||
let alloc_kind = this.get_alloc_info(alloc_id).kind;
|
||||
if !matches!(alloc_kind, AllocKind::LiveData) {
|
||||
assert_eq!(ptr_size, Size::ZERO); // we did the deref check above, size has to be 0 here
|
||||
// There's not actually any bytes here where accesses could even be tracked.
|
||||
@ -538,7 +538,7 @@ fn tb_expose_tag(&mut self, alloc_id: AllocId, tag: BorTag) -> InterpResult<'tcx
|
||||
// Function pointers and dead objects don't have an alloc_extra so we ignore them.
|
||||
// This is okay because accessing them is UB anyway, no need for any Tree Borrows checks.
|
||||
// NOT using `get_alloc_extra_mut` since this might be a read-only allocation!
|
||||
let (_size, _align, kind) = this.get_alloc_info(alloc_id);
|
||||
let kind = this.get_alloc_info(alloc_id).kind;
|
||||
match kind {
|
||||
AllocKind::LiveData => {
|
||||
// This should have alloc_extra data, but `get_alloc_extra` can still fail
|
||||
|
@ -1125,10 +1125,10 @@ fn extern_static_pointer(
|
||||
let Provenance::Concrete { alloc_id, .. } = ptr.provenance else {
|
||||
panic!("extern_statics cannot contain wildcards")
|
||||
};
|
||||
let (shim_size, shim_align, _kind) = ecx.get_alloc_info(alloc_id);
|
||||
let info = ecx.get_alloc_info(alloc_id);
|
||||
let def_ty = ecx.tcx.type_of(def_id).instantiate_identity();
|
||||
let extern_decl_layout = ecx.tcx.layout_of(ty::ParamEnv::empty().and(def_ty)).unwrap();
|
||||
if extern_decl_layout.size != shim_size || extern_decl_layout.align.abi != shim_align {
|
||||
if extern_decl_layout.size != info.size || extern_decl_layout.align.abi != info.align {
|
||||
throw_unsup_format!(
|
||||
"extern static `{link_name}` has been declared as `{krate}::{name}` \
|
||||
with a size of {decl_size} bytes and alignment of {decl_align} bytes, \
|
||||
@ -1138,8 +1138,8 @@ fn extern_static_pointer(
|
||||
krate = ecx.tcx.crate_name(def_id.krate),
|
||||
decl_size = extern_decl_layout.size.bytes(),
|
||||
decl_align = extern_decl_layout.align.abi.bytes(),
|
||||
shim_size = shim_size.bytes(),
|
||||
shim_align = shim_align.bytes(),
|
||||
shim_size = info.size.bytes(),
|
||||
shim_align = info.align.bytes(),
|
||||
)
|
||||
}
|
||||
interp_ok(ptr)
|
||||
|
@ -300,7 +300,7 @@ fn emulate_foreign_item_inner(
|
||||
let id = this.read_scalar(id)?.to_u64()?;
|
||||
let show_unnamed = this.read_scalar(show_unnamed)?.to_bool()?;
|
||||
if let Some(id) = std::num::NonZero::new(id).map(AllocId)
|
||||
&& this.get_alloc_info(id).2 == AllocKind::LiveData
|
||||
&& this.get_alloc_info(id).kind == AllocKind::LiveData
|
||||
{
|
||||
this.print_borrow_state(id, show_unnamed)?;
|
||||
} else {
|
||||
@ -409,7 +409,7 @@ fn emulate_foreign_item_inner(
|
||||
);
|
||||
}
|
||||
if let Ok((alloc_id, offset, ..)) = this.ptr_try_get_alloc_id(ptr, 0) {
|
||||
let (_size, alloc_align, _kind) = this.get_alloc_info(alloc_id);
|
||||
let alloc_align = this.get_alloc_info(alloc_id).align;
|
||||
// If the newly promised alignment is bigger than the native alignment of this
|
||||
// allocation, and bigger than the previously promised alignment, then set it.
|
||||
if align > alloc_align
|
||||
|
@ -41,6 +41,7 @@ pub mod rfs {
|
||||
pub use object;
|
||||
pub use regex;
|
||||
pub use serde_json;
|
||||
pub use similar;
|
||||
pub use wasmparser;
|
||||
// tidy-alphabetical-end
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
//@[s390x] needs-llvm-components: systemz
|
||||
//@ compile-flags: -Zmerge-functions=disabled
|
||||
|
||||
#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_experimental_arch)]
|
||||
#![feature(no_core, lang_items, rustc_attrs, repr_simd)]
|
||||
#![crate_type = "rlib"]
|
||||
#![no_core]
|
||||
#![allow(asm_sub_register, non_camel_case_types)]
|
||||
|
@ -3,7 +3,7 @@
|
||||
//@[s390x] needs-llvm-components: systemz
|
||||
|
||||
#![crate_type = "rlib"]
|
||||
#![feature(no_core, rustc_attrs, lang_items, asm_experimental_arch)]
|
||||
#![feature(no_core, rustc_attrs, lang_items)]
|
||||
#![no_core]
|
||||
|
||||
#[lang = "sized"]
|
||||
|
11
tests/codegen/debuginfo-proc-macro/auxiliary/macro_def.rs
Normal file
11
tests/codegen/debuginfo-proc-macro/auxiliary/macro_def.rs
Normal file
@ -0,0 +1,11 @@
|
||||
//@ force-host
|
||||
//@ no-prefer-dynamic
|
||||
#![crate_type = "proc-macro"]
|
||||
|
||||
extern crate proc_macro;
|
||||
use proc_macro::*;
|
||||
|
||||
#[proc_macro]
|
||||
pub fn square_twice(_item: TokenStream) -> TokenStream {
|
||||
"(square(env::vars().count() as i32), square(env::vars().count() as i32))".parse().unwrap()
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
//@ min-llvm-version: 19
|
||||
//@ compile-flags: -Cdebuginfo=2 -Copt-level=0 -Zmir-enable-passes=+Inline
|
||||
// MSVC is different because of the individual allocas.
|
||||
//@ ignore-msvc
|
||||
|
||||
//@ aux-build:macro_def.rs
|
||||
|
||||
// Find the variable.
|
||||
// CHECK-DAG: ![[#var_dbg:]] = !DILocalVariable(name: "n",{{( arg: 1,)?}} scope: ![[#var_scope:]]
|
||||
|
||||
// Find both dbg_declares. These will proceed the variable metadata, of course, so we're looking
|
||||
// backwards.
|
||||
// CHECK-DAG: dbg_declare(ptr %n.dbg.spill{{[0-9]}}, ![[#var_dbg]], !DIExpression(), ![[#var_loc2:]])
|
||||
// CHECK-DAG: dbg_declare(ptr %n.dbg.spill, ![[#var_dbg]], !DIExpression(), ![[#var_loc1:]])
|
||||
|
||||
// Find the first location definition, looking forwards again.
|
||||
// CHECK: ![[#var_loc1]] = !DILocation
|
||||
// CHECK-SAME: scope: ![[#var_scope:]], inlinedAt: ![[#var_inlinedAt1:]]
|
||||
|
||||
// Find the first location's inlinedAt
|
||||
// NB: If we fail here it's *probably* because we failed to produce two
|
||||
// different locations and ended up reusing an earlier one.
|
||||
// CHECK: ![[#var_inlinedAt1]] = !DILocation
|
||||
// CHECK-SAME: scope: ![[var_inlinedAt1_scope:]]
|
||||
|
||||
// Find the second location definition, still looking forwards.
|
||||
// NB: If we failed to produce two different locations, the test will
|
||||
// definitely fail by this point (if it hasn't already) because we won't
|
||||
// be able to find the same line again.
|
||||
// CHECK: ![[#var_loc2]] = !DILocation
|
||||
// CHECK-SAME: scope: ![[#var_scope]], inlinedAt: ![[#var_inlinedAt2:]]
|
||||
|
||||
// Find the second location's inlinedAt.
|
||||
// CHECK: ![[#var_inlinedAt2]] = !DILocation
|
||||
// CHECK-SAME: scope: ![[#var_inlinedAt2_scope:]]
|
||||
|
||||
// Finally, check that a discriminator was emitted for the second scope.
|
||||
// FIXMEkhuey ideally we would check that *either* scope has a discriminator
|
||||
// but I don't know that it's possible to check that with FileCheck.
|
||||
// CHECK: ![[#var_inlinedAt2_scope]] = !DILexicalBlockFile
|
||||
// CHECK-SAME: discriminator: [[#]]
|
||||
extern crate macro_def;
|
||||
|
||||
use std::env;
|
||||
|
||||
fn square(n: i32) -> i32 {
|
||||
n * n
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let (z1, z2) = macro_def::square_twice!();
|
||||
println!("{z1} == {z2}");
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
//@ compile-flags: -O -C no-prepopulate-passes
|
||||
#![crate_type = "lib"]
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(dyn_star)]
|
||||
#![feature(allocator_api)]
|
||||
|
||||
@ -143,13 +144,28 @@ pub fn indirect_struct(_: S) {}
|
||||
#[no_mangle]
|
||||
pub fn borrowed_struct(_: &S) {}
|
||||
|
||||
// CHECK: @option_borrow(ptr noalias noundef readonly align 4 dereferenceable_or_null(4) %x)
|
||||
// CHECK: @option_borrow(ptr noalias noundef readonly align 4 dereferenceable_or_null(4) %_x)
|
||||
#[no_mangle]
|
||||
pub fn option_borrow(x: Option<&i32>) {}
|
||||
pub fn option_borrow(_x: Option<&i32>) {}
|
||||
|
||||
// CHECK: @option_borrow_mut(ptr noalias noundef align 4 dereferenceable_or_null(4) %x)
|
||||
// CHECK: @option_borrow_mut(ptr noalias noundef align 4 dereferenceable_or_null(4) %_x)
|
||||
#[no_mangle]
|
||||
pub fn option_borrow_mut(x: Option<&mut i32>) {}
|
||||
pub fn option_borrow_mut(_x: Option<&mut i32>) {}
|
||||
|
||||
// Function that must NOT have `dereferenceable` or `align`.
|
||||
#[rustc_layout_scalar_valid_range_start(16)]
|
||||
pub struct RestrictedAddress(&'static i16);
|
||||
enum E {
|
||||
A(RestrictedAddress),
|
||||
B,
|
||||
C,
|
||||
}
|
||||
// If the `nonnull` ever goes missing, you might have to tweak the
|
||||
// scalar_valid_range on `RestrictedAddress` to get it back. You
|
||||
// might even have to add a `rustc_layout_scalar_valid_range_end`.
|
||||
// CHECK: @nonnull_and_nondereferenceable(ptr noundef nonnull %_x)
|
||||
#[no_mangle]
|
||||
pub fn nonnull_and_nondereferenceable(_x: E) {}
|
||||
|
||||
// CHECK: @raw_struct(ptr noundef %_1)
|
||||
#[no_mangle]
|
||||
|
@ -1,6 +1,10 @@
|
||||
//@ compile-flags: -O -Z merge-functions=disabled --edition=2021
|
||||
//@ only-x86_64
|
||||
// FIXME: Remove the `min-llvm-version`.
|
||||
//@ revisions: NINETEEN TWENTY
|
||||
//@[NINETEEN] min-llvm-version: 19
|
||||
//@[NINETEEN] ignore-llvm-version: 20-99
|
||||
//@[TWENTY] min-llvm-version: 20
|
||||
//@ min-llvm-version: 19
|
||||
|
||||
#![crate_type = "lib"]
|
||||
@ -13,8 +17,11 @@
|
||||
#[no_mangle]
|
||||
pub fn option_nop_match_32(x: Option<u32>) -> Option<u32> {
|
||||
// CHECK: start:
|
||||
// TWENTY-NEXT: %trunc = trunc nuw i32 %0 to i1
|
||||
// TWENTY-NEXT: %.2 = select i1 %trunc, i32 %1, i32 undef
|
||||
// CHECK-NEXT: [[REG1:%.*]] = insertvalue { i32, i32 } poison, i32 %0, 0
|
||||
// CHECK-NEXT: [[REG2:%.*]] = insertvalue { i32, i32 } [[REG1]], i32 %1, 1
|
||||
// NINETEEN-NEXT: [[REG2:%.*]] = insertvalue { i32, i32 } [[REG1]], i32 %1, 1
|
||||
// TWENTY-NEXT: [[REG2:%.*]] = insertvalue { i32, i32 } [[REG1]], i32 %.2, 1
|
||||
// CHECK-NEXT: ret { i32, i32 } [[REG2]]
|
||||
match x {
|
||||
Some(x) => Some(x),
|
||||
@ -26,6 +33,8 @@ pub fn option_nop_match_32(x: Option<u32>) -> Option<u32> {
|
||||
#[no_mangle]
|
||||
pub fn option_nop_traits_32(x: Option<u32>) -> Option<u32> {
|
||||
// CHECK: start:
|
||||
// TWENTY-NEXT: %trunc = trunc nuw i32 %0 to i1
|
||||
// TWENTY-NEXT: %.1 = select i1 %trunc, i32 %1, i32 undef
|
||||
// CHECK-NEXT: insertvalue { i32, i32 }
|
||||
// CHECK-NEXT: insertvalue { i32, i32 }
|
||||
// CHECK-NEXT: ret { i32, i32 }
|
||||
|
29
tests/run-make/rustc-help/help-v.diff
Normal file
29
tests/run-make/rustc-help/help-v.diff
Normal file
@ -0,0 +1,29 @@
|
||||
@@ -51,10 +51,27 @@
|
||||
Set a codegen option
|
||||
-V, --version Print version info and exit
|
||||
-v, --verbose Use verbose output
|
||||
+ --extern NAME[=PATH]
|
||||
+ Specify where an external rust library is located
|
||||
+ --sysroot PATH Override the system root
|
||||
+ --error-format human|json|short
|
||||
+ How errors and other messages are produced
|
||||
+ --json CONFIG Configure the JSON output of the compiler
|
||||
+ --color auto|always|never
|
||||
+ Configure coloring of output:
|
||||
+ auto = colorize, if output goes to a tty (default);
|
||||
+ always = always colorize output;
|
||||
+ never = never colorize output
|
||||
+ --diagnostic-width WIDTH
|
||||
+ Inform rustc of the width of the output so that
|
||||
+ diagnostics can be truncated to fit
|
||||
+ --remap-path-prefix FROM=TO
|
||||
+ Remap source names in all output (compiler messages
|
||||
+ and output files)
|
||||
+ @path Read newline separated options from `path`
|
||||
|
||||
Additional help:
|
||||
-C help Print codegen options
|
||||
-W help Print 'lint' options and default settings
|
||||
-Z help Print unstable compiler options
|
||||
- --help -v Print the full set of options rustc accepts
|
||||
|
77
tests/run-make/rustc-help/help-v.stdout
Normal file
77
tests/run-make/rustc-help/help-v.stdout
Normal file
@ -0,0 +1,77 @@
|
||||
Usage: rustc [OPTIONS] INPUT
|
||||
|
||||
Options:
|
||||
-h, --help Display this message
|
||||
--cfg SPEC Configure the compilation environment.
|
||||
SPEC supports the syntax `NAME[="VALUE"]`.
|
||||
--check-cfg SPEC
|
||||
Provide list of expected cfgs for checking
|
||||
-L [KIND=]PATH Add a directory to the library search path. The
|
||||
optional KIND can be one of dependency, crate, native,
|
||||
framework, or all (the default).
|
||||
-l [KIND[:MODIFIERS]=]NAME[:RENAME]
|
||||
Link the generated crate(s) to the specified native
|
||||
library NAME. The optional KIND can be one of
|
||||
static, framework, or dylib (the default).
|
||||
Optional comma separated MODIFIERS
|
||||
(bundle|verbatim|whole-archive|as-needed)
|
||||
may be specified each with a prefix of either '+' to
|
||||
enable or '-' to disable.
|
||||
--crate-type [bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]
|
||||
Comma separated list of types of crates
|
||||
for the compiler to emit
|
||||
--crate-name NAME
|
||||
Specify the name of the crate being built
|
||||
--edition 2015|2018|2021|2024
|
||||
Specify which edition of the compiler to use when
|
||||
compiling code. The default is 2015 and the latest
|
||||
stable edition is 2021.
|
||||
--emit [asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]
|
||||
Comma separated list of types of output for the
|
||||
compiler to emit
|
||||
--print [crate-name|file-names|sysroot|target-libdir|cfg|check-cfg|calling-conventions|target-list|target-cpus|target-features|relocation-models|code-models|tls-models|target-spec-json|all-target-specs-json|native-static-libs|stack-protector-strategies|link-args|deployment-target]
|
||||
Compiler information to print on stdout
|
||||
-g Equivalent to -C debuginfo=2
|
||||
-O Equivalent to -C opt-level=2
|
||||
-o FILENAME Write output to <filename>
|
||||
--out-dir DIR Write output to compiler-chosen filename in <dir>
|
||||
--explain OPT Provide a detailed explanation of an error message
|
||||
--test Build a test harness
|
||||
--target TARGET Target triple for which the code is compiled
|
||||
-A, --allow LINT Set lint allowed
|
||||
-W, --warn LINT Set lint warnings
|
||||
--force-warn LINT
|
||||
Set lint force-warn
|
||||
-D, --deny LINT Set lint denied
|
||||
-F, --forbid LINT Set lint forbidden
|
||||
--cap-lints LEVEL
|
||||
Set the most restrictive lint level. More restrictive
|
||||
lints are capped at this level
|
||||
-C, --codegen OPT[=VALUE]
|
||||
Set a codegen option
|
||||
-V, --version Print version info and exit
|
||||
-v, --verbose Use verbose output
|
||||
--extern NAME[=PATH]
|
||||
Specify where an external rust library is located
|
||||
--sysroot PATH Override the system root
|
||||
--error-format human|json|short
|
||||
How errors and other messages are produced
|
||||
--json CONFIG Configure the JSON output of the compiler
|
||||
--color auto|always|never
|
||||
Configure coloring of output:
|
||||
auto = colorize, if output goes to a tty (default);
|
||||
always = always colorize output;
|
||||
never = never colorize output
|
||||
--diagnostic-width WIDTH
|
||||
Inform rustc of the width of the output so that
|
||||
diagnostics can be truncated to fit
|
||||
--remap-path-prefix FROM=TO
|
||||
Remap source names in all output (compiler messages
|
||||
and output files)
|
||||
@path Read newline separated options from `path`
|
||||
|
||||
Additional help:
|
||||
-C help Print codegen options
|
||||
-W help Print 'lint' options and default settings
|
||||
-Z help Print unstable compiler options
|
||||
|
60
tests/run-make/rustc-help/help.stdout
Normal file
60
tests/run-make/rustc-help/help.stdout
Normal file
@ -0,0 +1,60 @@
|
||||
Usage: rustc [OPTIONS] INPUT
|
||||
|
||||
Options:
|
||||
-h, --help Display this message
|
||||
--cfg SPEC Configure the compilation environment.
|
||||
SPEC supports the syntax `NAME[="VALUE"]`.
|
||||
--check-cfg SPEC
|
||||
Provide list of expected cfgs for checking
|
||||
-L [KIND=]PATH Add a directory to the library search path. The
|
||||
optional KIND can be one of dependency, crate, native,
|
||||
framework, or all (the default).
|
||||
-l [KIND[:MODIFIERS]=]NAME[:RENAME]
|
||||
Link the generated crate(s) to the specified native
|
||||
library NAME. The optional KIND can be one of
|
||||
static, framework, or dylib (the default).
|
||||
Optional comma separated MODIFIERS
|
||||
(bundle|verbatim|whole-archive|as-needed)
|
||||
may be specified each with a prefix of either '+' to
|
||||
enable or '-' to disable.
|
||||
--crate-type [bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]
|
||||
Comma separated list of types of crates
|
||||
for the compiler to emit
|
||||
--crate-name NAME
|
||||
Specify the name of the crate being built
|
||||
--edition 2015|2018|2021|2024
|
||||
Specify which edition of the compiler to use when
|
||||
compiling code. The default is 2015 and the latest
|
||||
stable edition is 2021.
|
||||
--emit [asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]
|
||||
Comma separated list of types of output for the
|
||||
compiler to emit
|
||||
--print [crate-name|file-names|sysroot|target-libdir|cfg|check-cfg|calling-conventions|target-list|target-cpus|target-features|relocation-models|code-models|tls-models|target-spec-json|all-target-specs-json|native-static-libs|stack-protector-strategies|link-args|deployment-target]
|
||||
Compiler information to print on stdout
|
||||
-g Equivalent to -C debuginfo=2
|
||||
-O Equivalent to -C opt-level=2
|
||||
-o FILENAME Write output to <filename>
|
||||
--out-dir DIR Write output to compiler-chosen filename in <dir>
|
||||
--explain OPT Provide a detailed explanation of an error message
|
||||
--test Build a test harness
|
||||
--target TARGET Target triple for which the code is compiled
|
||||
-A, --allow LINT Set lint allowed
|
||||
-W, --warn LINT Set lint warnings
|
||||
--force-warn LINT
|
||||
Set lint force-warn
|
||||
-D, --deny LINT Set lint denied
|
||||
-F, --forbid LINT Set lint forbidden
|
||||
--cap-lints LEVEL
|
||||
Set the most restrictive lint level. More restrictive
|
||||
lints are capped at this level
|
||||
-C, --codegen OPT[=VALUE]
|
||||
Set a codegen option
|
||||
-V, --version Print version info and exit
|
||||
-v, --verbose Use verbose output
|
||||
|
||||
Additional help:
|
||||
-C help Print codegen options
|
||||
-W help Print 'lint' options and default settings
|
||||
-Z help Print unstable compiler options
|
||||
--help -v Print the full set of options rustc accepts
|
||||
|
21
tests/run-make/rustc-help/rmake.rs
Normal file
21
tests/run-make/rustc-help/rmake.rs
Normal file
@ -0,0 +1,21 @@
|
||||
// Tests `rustc --help` and similar invocations against snapshots and each other.
|
||||
|
||||
use run_make_support::{bare_rustc, diff, similar};
|
||||
|
||||
fn main() {
|
||||
// `rustc --help`
|
||||
let help = bare_rustc().arg("--help").run().stdout_utf8();
|
||||
diff().expected_file("help.stdout").actual_text("(rustc --help)", &help).run();
|
||||
|
||||
// `rustc` should be the same as `rustc --help`
|
||||
let bare = bare_rustc().run().stdout_utf8();
|
||||
diff().expected_text("(rustc --help)", &help).actual_text("(rustc)", &bare).run();
|
||||
|
||||
// `rustc --help -v` should give a similar but longer help message
|
||||
let help_v = bare_rustc().arg("--help").arg("-v").run().stdout_utf8();
|
||||
diff().expected_file("help-v.stdout").actual_text("(rustc --help -v)", &help_v).run();
|
||||
|
||||
// Check the diff between `rustc --help` and `rustc --help -v`.
|
||||
let help_v_diff = similar::TextDiff::from_lines(&help, &help_v).unified_diff().to_string();
|
||||
diff().expected_file("help-v.diff").actual_text("actual", &help_v_diff).run();
|
||||
}
|
78
tests/rustdoc/hidden-implementors-90781.rs
Normal file
78
tests/rustdoc/hidden-implementors-90781.rs
Normal file
@ -0,0 +1,78 @@
|
||||
//@ compile-flags: -Z unstable-options --document-hidden-items --document-private-items
|
||||
|
||||
// regression test for https://github.com/rust-lang/rust/issues/90781
|
||||
#![crate_name = "foo"]
|
||||
|
||||
//@ has foo/trait.TPubVis.html
|
||||
//@ has - '//*[@id="implementors-list"]' 'HidPriv'
|
||||
//@ has - '//*[@id="implementors-list"]' 'HidPub'
|
||||
//@ has - '//*[@id="implementors-list"]' 'VisPriv'
|
||||
//@ has - '//*[@id="implementors-list"]' 'VisPub'
|
||||
pub trait TPubVis {}
|
||||
|
||||
//@ has foo/trait.TPubHidden.html
|
||||
//@ has - '//*[@id="implementors-list"]' 'HidPriv'
|
||||
//@ has - '//*[@id="implementors-list"]' 'HidPub'
|
||||
//@ has - '//*[@id="implementors-list"]' 'VisPriv'
|
||||
//@ has - '//*[@id="implementors-list"]' 'VisPub'
|
||||
#[doc(hidden)]
|
||||
pub trait TPubHidden {}
|
||||
|
||||
//@ has foo/trait.TPrivVis.html
|
||||
//@ has - '//*[@id="implementors-list"]' 'HidPriv'
|
||||
//@ has - '//*[@id="implementors-list"]' 'HidPub'
|
||||
//@ has - '//*[@id="implementors-list"]' 'VisPriv'
|
||||
//@ has - '//*[@id="implementors-list"]' 'VisPub'
|
||||
trait TPrivVis {}
|
||||
|
||||
#[doc(hidden)]
|
||||
//@ has foo/trait.TPrivHidden.html
|
||||
//@ has - '//*[@id="impl-TPrivHidden-for-HidPriv"]' 'HidPriv'
|
||||
//@ has - '//*[@id="impl-TPrivHidden-for-HidPub"]' 'HidPub'
|
||||
//@ has - '//*[@id="impl-TPrivHidden-for-VisPriv"]' 'VisPriv'
|
||||
//@ has - '//*[@id="impl-TPrivHidden-for-VisPub"]' 'VisPub'
|
||||
trait TPrivHidden {}
|
||||
|
||||
//@ has foo/struct.VisPub.html
|
||||
//@ has - '//*[@id="trait-implementations-list"]' 'TPrivHidden'
|
||||
//@ has - '//*[@id="trait-implementations-list"]' 'TPrivVis'
|
||||
//@ has - '//*[@id="trait-implementations-list"]' 'TPubHidden'
|
||||
//@ has - '//*[@id="trait-implementations-list"]' 'TPubVis'
|
||||
pub struct VisPub;
|
||||
|
||||
//@ has foo/struct.VisPriv.html
|
||||
//@ has - '//*[@id="trait-implementations-list"]' 'TPrivHidden'
|
||||
//@ has - '//*[@id="trait-implementations-list"]' 'TPrivVis'
|
||||
//@ has - '//*[@id="trait-implementations-list"]' 'TPubHidden'
|
||||
//@ has - '//*[@id="trait-implementations-list"]' 'TPubVis'
|
||||
struct VisPriv;
|
||||
|
||||
//@ has foo/struct.HidPub.html
|
||||
//@ has - '//*[@id="trait-implementations-list"]' 'TPrivHidden'
|
||||
//@ has - '//*[@id="trait-implementations-list"]' 'TPrivVis'
|
||||
//@ has - '//*[@id="trait-implementations-list"]' 'TPubHidden'
|
||||
//@ has - '//*[@id="trait-implementations-list"]' 'TPubVis'
|
||||
#[doc(hidden)]
|
||||
pub struct HidPub;
|
||||
|
||||
//@ has foo/struct.HidPriv.html
|
||||
//@ has - '//*[@id="trait-implementations-list"]' 'TPrivHidden'
|
||||
//@ has - '//*[@id="trait-implementations-list"]' 'TPrivVis'
|
||||
//@ has - '//*[@id="trait-implementations-list"]' 'TPubHidden'
|
||||
//@ has - '//*[@id="trait-implementations-list"]' 'TPubVis'
|
||||
#[doc(hidden)]
|
||||
struct HidPriv;
|
||||
|
||||
macro_rules! implement {
|
||||
($trait:ident - $($struct:ident)+) => {
|
||||
$(
|
||||
impl $trait for $struct {}
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
implement!(TPubVis - VisPub VisPriv HidPub HidPriv);
|
||||
implement!(TPubHidden - VisPub VisPriv HidPub HidPriv);
|
||||
implement!(TPrivVis - VisPub VisPriv HidPub HidPriv);
|
||||
implement!(TPrivHidden - VisPub VisPriv HidPub HidPriv);
|
43
tests/ui/abi/sparcv8plus.rs
Normal file
43
tests/ui/abi/sparcv8plus.rs
Normal file
@ -0,0 +1,43 @@
|
||||
//@ revisions: sparc sparcv8plus sparc_cpu_v9 sparc_feature_v8plus sparc_cpu_v9_feature_v8plus
|
||||
//@[sparc] compile-flags: --target sparc-unknown-none-elf
|
||||
//@[sparc] needs-llvm-components: sparc
|
||||
//@[sparcv8plus] compile-flags: --target sparc-unknown-linux-gnu
|
||||
//@[sparcv8plus] needs-llvm-components: sparc
|
||||
//@[sparc_cpu_v9] compile-flags: --target sparc-unknown-none-elf -C target-cpu=v9
|
||||
//@[sparc_cpu_v9] needs-llvm-components: sparc
|
||||
//@[sparc_feature_v8plus] compile-flags: --target sparc-unknown-none-elf -C target-feature=+v8plus
|
||||
//@[sparc_feature_v8plus] needs-llvm-components: sparc
|
||||
//@[sparc_cpu_v9_feature_v8plus] compile-flags: --target sparc-unknown-none-elf -C target-cpu=v9 -C target-feature=+v8plus
|
||||
//@[sparc_cpu_v9_feature_v8plus] needs-llvm-components: sparc
|
||||
//@ min-llvm-version: 19
|
||||
|
||||
#![crate_type = "rlib"]
|
||||
#![feature(no_core, rustc_attrs, lang_items)]
|
||||
#![no_core]
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
#[lang = "copy"]
|
||||
trait Copy {}
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! compile_error {
|
||||
() => {};
|
||||
}
|
||||
|
||||
#[cfg(all(not(target_feature = "v8plus"), not(target_feature = "v9")))]
|
||||
compile_error!("-v8plus,-v9");
|
||||
//[sparc]~^ ERROR -v8plus,-v9
|
||||
|
||||
// FIXME: sparc_cpu_v9 should be in "-v8plus,+v9" group (fixed in LLVM 20)
|
||||
#[cfg(all(target_feature = "v8plus", target_feature = "v9"))]
|
||||
compile_error!("+v8plus,+v9");
|
||||
//[sparcv8plus,sparc_cpu_v9_feature_v8plus,sparc_cpu_v9]~^ ERROR +v8plus,+v9
|
||||
|
||||
// FIXME: should be rejected
|
||||
#[cfg(all(target_feature = "v8plus", not(target_feature = "v9")))]
|
||||
compile_error!("+v8plus,-v9 (FIXME)");
|
||||
//[sparc_feature_v8plus]~^ ERROR +v8plus,-v9 (FIXME)
|
||||
|
||||
#[cfg(all(not(target_feature = "v8plus"), target_feature = "v9"))]
|
||||
compile_error!("-v8plus,+v9");
|
8
tests/ui/abi/sparcv8plus.sparc.stderr
Normal file
8
tests/ui/abi/sparcv8plus.sparc.stderr
Normal file
@ -0,0 +1,8 @@
|
||||
error: -v8plus,-v9
|
||||
--> $DIR/sparcv8plus.rs:29:1
|
||||
|
|
||||
LL | compile_error!("-v8plus,-v9");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user