Merge pull request #4021 from RalfJung/rustup

Rustup
This commit is contained in:
Ralf Jung 2024-11-10 09:29:44 +00:00 committed by GitHub
commit a839fbf0a1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
168 changed files with 5563 additions and 2639 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
[toolchain]
channel = "nightly-2024-11-02"
channel = "nightly-2024-11-09"
components = ["rust-src", "rustc-dev", "llvm-tools"]
profile = "minimal"

View File

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

View File

@ -3,7 +3,7 @@
use std::borrow::Cow;
use rustc_target::abi::call::PassMode;
use rustc_target::callconv::PassMode;
use crate::prelude::*;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,7 +2,7 @@
//! operations.
use cranelift_codegen::ir::immediates::Offset32;
use rustc_target::abi::Align;
use rustc_abi::Align;
use crate::prelude::*;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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")
// # 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);
}
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.
// # Dead pointers
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)
}
}
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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 = "...")`.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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)
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)
})
}
fn unstable<F>(name: S, f: F) -> R
where
F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
{
RustcOptGroup::unstable(name, f)
OptionKind::FlagMulti => {
assert_eq!(hint, "");
Box::new(move |opts: &mut getopts::Options| {
opts.optflagmulti(short_name, long_name, desc)
})
}
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))
},
}
}
@ -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
"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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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), &[

View File

@ -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,
_ => &[],
}
}

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -215,220 +215,223 @@ 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(
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.",
"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, 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(
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",
)
}),
unstable("extern-html-root-takes-precedence", |o| {
o.optflagmulti(
),
opt(
Unstable,
FlagMulti,
"",
"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(
"",
),
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",
)
}),
stable("target", |o| o.optopt("", "target", "target triple to document", "TRIPLE")),
stable("markdown-css", |o| {
o.optmulti(
),
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",
)
}),
stable("html-in-header", |o| {
o.optmulti(
),
opt(
Stable,
Multi,
"",
"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(
),
opt(
Stable,
Multi,
"",
"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(
),
opt(
Stable,
Multi,
"",
"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(
),
opt(
Unstable,
Multi,
"",
"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(
),
opt(
Unstable,
Multi,
"",
"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(
),
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!",
"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(
),
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",
)
}),
unstable("display-doctest-warnings", |o| {
o.optflagmulti(
),
opt(
Unstable,
FlagMulti,
"",
"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(
"",
),
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",
)
}),
stable("default-theme", |o| {
o.optopt(
"",
),
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",
)
}),
unstable("default-setting", |o| {
o.optmulti(
),
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]",
)
}),
stable("theme", |o| {
o.optmulti(
),
opt(
Stable,
Multi,
"",
"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(
),
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\"",
"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(
),
opt(
Stable,
Opt,
"",
"edition",
"edition to use when compiling rust code (default: 2015)",
"EDITION",
)
}),
stable("color", |o| {
o.optopt(
),
opt(
Stable,
Opt,
"",
"color",
"Configure coloring of output:
@ -436,256 +439,258 @@ fn opts() -> Vec<RustcOptGroup> {
always = always colorize output;
never = never colorize output",
"auto|always|never",
)
}),
stable("error-format", |o| {
o.optopt(
),
opt(
Stable,
Opt,
"",
"error-format",
"How errors and other messages are produced",
"human|json|short",
)
}),
stable("diagnostic-width", |o| {
o.optopt(
),
opt(
Stable,
Opt,
"",
"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(
),
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.",
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(
),
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",
)
}),
unstable("persist-doctests", |o| {
o.optopt(
),
opt(
Unstable,
Opt,
"",
"persist-doctests",
"Directory to persist doctest executables into",
"PATH",
)
}),
unstable("show-coverage", |o| {
o.optflagmulti(
),
opt(
Unstable,
FlagMulti,
"",
"show-coverage",
"calculate percentage of public items with documentation",
)
}),
unstable("enable-per-target-ignores", |o| {
o.optflagmulti(
"",
),
opt(
Unstable,
FlagMulti,
"",
"enable-per-target-ignores",
"parse ignore-foo for ignoring doctests on a per-target basis",
)
}),
unstable("runtool", |o| {
o.optopt(
"",
),
opt(
Unstable,
Opt,
"",
"runtool",
"",
"The tool to run tests with when building for a different target than host",
)
}),
unstable("runtool-arg", |o| {
o.optmulti(
),
opt(
Unstable,
Multi,
"",
"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(
),
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",
)
}),
unstable("check", |o| o.optflagmulti("", "check", "Run rustdoc checks")),
unstable("generate-redirect-map", |o| {
o.optflagmulti(
),
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",
)
}),
unstable("emit", |o| {
o.optmulti(
"",
),
opt(
Unstable,
Multi,
"",
"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(
),
opt(Unstable, FlagMulti, "", "no-run", "Compile doctests without running them", ""),
opt(
Unstable,
Multi,
"",
"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(
),
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",
)
}),
unstable("scrape-examples-output-path", |o| {
o.optopt(
"",
),
opt(
Unstable,
Opt,
"",
"scrape-examples-output-path",
"",
"collect function call information and output at the given path",
)
}),
unstable("scrape-examples-target-crate", |o| {
o.optmulti(
),
opt(
Unstable,
Multi,
"",
"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(
),
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)",
)
}),
unstable("merge", |o| {
o.optopt(
),
opt(
Unstable,
Opt,
"",
"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
"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",
)
}),
unstable("parts-out-dir", |o| {
o.optopt(
),
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>",
)
}),
unstable("include-parts-dir", |o| {
o.optmulti(
),
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(
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",
"removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
"DIR",
)
}),
stable("passes", |o| {
o.optmulti(
),
opt(
Stable,
Multi,
"",
"passes",
"removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> \
for more information",
"removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
"PASSES",
)
}),
stable("plugins", |o| {
o.optmulti(
),
opt(
Stable,
Multi,
"",
"plugins",
"removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> \
for more information",
"removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
"PLUGINS",
)
}),
stable("no-default", |o| {
o.optflagmulti(
),
opt(
Stable,
FlagMulti,
"",
"no-defaults",
"removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> \
for more information",
)
}),
stable("r", |o| {
o.optopt(
"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",
"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, 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

View File

@ -1 +1 @@
328b759142ddeae96da83176f103200009d3e3f1
668959740f97e7a22ae340742886d330ab63950f

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View 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

View 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

View 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

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

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

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

Some files were not shown because too many files have changed in this diff Show More