sym::simd => Some(ReprSimd),
sym::transparent => Some(ReprTransparent),
sym::no_niche => Some(ReprNoNiche),
+ sym::align => {
+ let mut err = struct_span_err!(
+ diagnostic,
+ item.span(),
+ E0589,
+ "invalid `repr(align)` attribute: `align` needs an argument"
+ );
+ err.span_suggestion(
+ item.span(),
+ "supply an argument here",
+ "align(...)".to_string(),
+ Applicability::HasPlaceholders,
+ );
+ err.emit();
+ recognised = true;
+ None
+ }
name => int_type_of_word(name).map(ReprInt),
};
Ok(literal) => acc.push(ReprPacked(literal)),
Err(message) => literal_error = Some(message),
};
+ } else if matches!(name, sym::C | sym::simd | sym::transparent | sym::no_niche)
+ || int_type_of_word(name).is_some()
+ {
+ recognised = true;
+ struct_span_err!(
+ diagnostic,
+ item.span(),
+ E0552,
+ "invalid representation hint: `{}` does not take a parenthesized argument list",
+ name.to_ident_string(),
+ ).emit();
}
if let Some(literal_error) = literal_error {
struct_span_err!(
diagnostic,
item.span(),
E0589,
- "invalid `repr(align)` attribute: {}",
+ "invalid `repr({})` attribute: {}",
+ name.to_ident_string(),
literal_error
)
.emit();
}
} else if let Some(meta_item) = item.meta_item() {
- if meta_item.has_name(sym::align) {
- if let MetaItemKind::NameValue(ref value) = meta_item.kind {
+ if let MetaItemKind::NameValue(ref value) = meta_item.kind {
+ if meta_item.has_name(sym::align) || meta_item.has_name(sym::packed) {
+ let name = meta_item.name_or_empty().to_ident_string();
recognised = true;
let mut err = struct_span_err!(
diagnostic,
item.span(),
E0693,
- "incorrect `repr(align)` attribute format"
+ "incorrect `repr({})` attribute format",
+ name,
);
match value.kind {
ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => {
err.span_suggestion(
item.span(),
"use parentheses instead",
- format!("align({})", int),
+ format!("{}({})", name, int),
Applicability::MachineApplicable,
);
}
err.span_suggestion(
item.span(),
"use parentheses instead",
- format!("align({})", s),
+ format!("{}({})", name, s),
Applicability::MachineApplicable,
);
}
_ => {}
}
err.emit();
+ } else {
+ if matches!(
+ meta_item.name_or_empty(),
+ sym::C | sym::simd | sym::transparent | sym::no_niche
+ ) || int_type_of_word(meta_item.name_or_empty()).is_some()
+ {
+ recognised = true;
+ struct_span_err!(
+ diagnostic,
+ meta_item.span,
+ E0552,
+ "invalid representation hint: `{}` does not take a value",
+ meta_item.name_or_empty().to_ident_string(),
+ )
+ .emit();
+ }
+ }
+ } else if let MetaItemKind::List(_) = meta_item.kind {
+ if meta_item.has_name(sym::align) {
+ recognised = true;
+ struct_span_err!(
+ diagnostic,
+ meta_item.span,
+ E0693,
+ "incorrect `repr(align)` attribute format: \
+ `align` takes exactly one argument in parentheses"
+ )
+ .emit();
+ } else if meta_item.has_name(sym::packed) {
+ recognised = true;
+ struct_span_err!(
+ diagnostic,
+ meta_item.span,
+ E0552,
+ "incorrect `repr(packed)` attribute format: \
+ `packed` takes exactly one parenthesized argument, \
+ or no parentheses at all"
+ )
+ .emit();
+ } else if matches!(
+ meta_item.name_or_empty(),
+ sym::C | sym::simd | sym::transparent | sym::no_niche
+ ) || int_type_of_word(meta_item.name_or_empty()).is_some()
+ {
+ recognised = true;
+ struct_span_err!(
+ diagnostic,
+ meta_item.span,
+ E0552,
+ "invalid representation hint: `{}` does not take a parenthesized argument list",
+ meta_item.name_or_empty().to_ident_string(),
+ ).emit();
}
}
}
if !recognised {
- // Not a word we recognize
- diagnostic.delay_span_bug(item.span(), "unrecognized representation hint");
+ // Not a word we recognize. This will be caught and reported by
+ // the `check_mod_attrs` pass, but this pass doesn't always run
+ // (e.g. if we only pretty-print the source), so we have to gate
+ // the `delay_span_bug` call as follows:
+ if sess.opts.pretty.map_or(true, |pp| pp.needs_analysis()) {
+ diagnostic.delay_span_bug(item.span(), "unrecognized representation hint");
+ }
}
}
}
use rustc_codegen_ssa::back::archive::{find_library, ArchiveBuilder};
use rustc_codegen_ssa::{looks_like_rust_object_file, METADATA_FILENAME};
use rustc_data_structures::temp_dir::MaybeTempDir;
-use rustc_middle::middle::cstore::DllImport;
+use rustc_middle::middle::cstore::{DllCallingConvention, DllImport};
use rustc_session::Session;
use rustc_span::symbol::Symbol;
// have any \0 characters
let import_name_vector: Vec<CString> = dll_imports
.iter()
- .map(if self.config.sess.target.arch == "x86" {
- |import: &DllImport| CString::new(format!("_{}", import.name.to_string())).unwrap()
- } else {
- |import: &DllImport| CString::new(import.name.to_string()).unwrap()
+ .map(|import: &DllImport| {
+ if self.config.sess.target.arch == "x86" {
+ LlvmArchiveBuilder::i686_decorated_name(import)
+ } else {
+ CString::new(import.name.to_string()).unwrap()
+ }
})
.collect();
ret
}
}
+
+ fn i686_decorated_name(import: &DllImport) -> CString {
+ let name = import.name;
+ // We verified during construction that `name` does not contain any NULL characters, so the
+ // conversion to CString is guaranteed to succeed.
+ CString::new(match import.calling_convention {
+ DllCallingConvention::C => format!("_{}", name),
+ DllCallingConvention::Stdcall(arg_list_size) => format!("_{}@{}", name, arg_list_size),
+ DllCallingConvention::Fastcall(arg_list_size) => format!("@{}@{}", name, arg_list_size),
+ DllCallingConvention::Vectorcall(arg_list_size) => {
+ format!("{}@@{}", name, arg_list_size)
+ }
+ })
+ .unwrap()
+ }
}
fn string_to_io_error(s: String) -> io::Error {
use rustc_errors::Handler;
use rustc_fs_util::fix_windows_verbatim_for_gcc;
use rustc_hir::def_id::CrateNum;
-use rustc_middle::middle::cstore::DllImport;
+use rustc_middle::middle::cstore::{DllCallingConvention, DllImport};
use rustc_middle::middle::dependency_format::Linkage;
use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip};
use rustc_session::config::{OutputFilenames, OutputType, PrintRequest};
use object::{Architecture, BinaryFormat, Endianness, FileFlags, SectionFlags, SectionKind};
use tempfile::Builder as TempFileBuilder;
-use std::cmp::Ordering;
use std::ffi::OsString;
+use std::iter::FromIterator;
use std::path::{Path, PathBuf};
use std::process::{ExitStatus, Output, Stdio};
use std::{ascii, char, env, fmt, fs, io, mem, str};
}
for (raw_dylib_name, raw_dylib_imports) in
- collate_raw_dylibs(&codegen_results.crate_info.used_libraries)
+ collate_raw_dylibs(sess, &codegen_results.crate_info.used_libraries)
{
ab.inject_dll_import_lib(&raw_dylib_name, &raw_dylib_imports, tmpdir);
}
/// then the CodegenResults value contains one NativeLib instance for each block. However, the
/// linker appears to expect only a single import library for each library used, so we need to
/// collate the symbols together by library name before generating the import libraries.
-fn collate_raw_dylibs(used_libraries: &[NativeLib]) -> Vec<(String, Vec<DllImport>)> {
- let mut dylib_table: FxHashMap<String, FxHashSet<Symbol>> = FxHashMap::default();
+fn collate_raw_dylibs(
+ sess: &Session,
+ used_libraries: &[NativeLib],
+) -> Vec<(String, Vec<DllImport>)> {
+ let mut dylib_table: FxHashMap<String, FxHashSet<DllImport>> = FxHashMap::default();
for lib in used_libraries {
if lib.kind == NativeLibKind::RawDylib {
} else {
format!("{}.dll", name)
};
- dylib_table
- .entry(name)
- .or_default()
- .extend(lib.dll_imports.iter().map(|import| import.name));
+ dylib_table.entry(name).or_default().extend(lib.dll_imports.iter().cloned());
}
}
- // FIXME: when we add support for ordinals, fix this to propagate ordinals. Also figure out
- // what we should do if we have two DllImport values with the same name but different
- // ordinals.
- let mut result = dylib_table
+ // Rustc already signals an error if we have two imports with the same name but different
+ // calling conventions (or function signatures), so we don't have pay attention to those
+ // when ordering.
+ // FIXME: when we add support for ordinals, figure out if we need to do anything if we
+ // have two DllImport values with the same name but different ordinals.
+ let mut result: Vec<(String, Vec<DllImport>)> = dylib_table
.into_iter()
- .map(|(lib_name, imported_names)| {
- let mut names = imported_names
- .iter()
- .map(|name| DllImport { name: *name, ordinal: None })
- .collect::<Vec<_>>();
- names.sort_unstable_by(|a: &DllImport, b: &DllImport| {
- match a.name.as_str().cmp(&b.name.as_str()) {
- Ordering::Equal => a.ordinal.cmp(&b.ordinal),
- x => x,
- }
- });
- (lib_name, names)
+ .map(|(lib_name, import_table)| {
+ let mut imports = Vec::from_iter(import_table.into_iter());
+ imports.sort_unstable_by_key(|x: &DllImport| x.name.as_str());
+ (lib_name, imports)
})
.collect::<Vec<_>>();
result.sort_unstable_by(|a: &(String, Vec<DllImport>), b: &(String, Vec<DllImport>)| {
a.0.cmp(&b.0)
});
+ let result = result;
+
+ // Check for multiple imports with the same name but different calling conventions or
+ // (when relevant) argument list sizes. Rustc only signals an error for this if the
+ // declarations are at the same scope level; if one shadows the other, we only get a lint
+ // warning.
+ for (library, imports) in &result {
+ let mut import_table: FxHashMap<Symbol, DllCallingConvention> = FxHashMap::default();
+ for import in imports {
+ if let Some(old_convention) =
+ import_table.insert(import.name, import.calling_convention)
+ {
+ if import.calling_convention != old_convention {
+ sess.span_fatal(
+ import.span,
+ &format!(
+ "multiple definitions of external function `{}` from library `{}` have different calling conventions",
+ import.name,
+ library,
+ ));
+ }
+ }
+ }
+ }
+
result
}
/// Allows accessing fields of unions inside `const` functions.
(active, const_fn_union, "1.27.0", Some(51909), None),
- /// Allows casting raw pointers to `usize` during const eval.
- (active, const_raw_ptr_to_usize_cast, "1.27.0", Some(51910), None),
-
/// Allows dereferencing raw pointers during const eval.
(active, const_raw_ptr_deref, "1.27.0", Some(51911), None),
(removed, external_doc, "1.54.0", Some(44732), None,
Some("use #[doc = include_str!(\"filename\")] instead, which handles macro invocations")),
+ /// Allows casting raw pointers to `usize` during const eval.
+ (removed, const_raw_ptr_to_usize_cast, "1.55.0", Some(51910), None,
+ Some("at compile-time, pointers do not have an integer value, so these casts cannot be properly supported")),
+
// -------------------------------------------------------------------------
// feature-group-end: removed features
// -------------------------------------------------------------------------
self.check_missing_docs_attrs(cx, hir::CRATE_HIR_ID, krate.item.inner, "the", "crate");
for macro_def in krate.exported_macros {
+ // Non exported macros should be skipped, since `missing_docs` only
+ // applies to externally visible items.
+ if !cx.access_levels.is_exported(macro_def.hir_id()) {
+ continue;
+ }
+
let attrs = cx.tcx.hir().attrs(macro_def.hir_id());
let has_doc = attrs.iter().any(|a| has_doc(cx.sess(), a));
if !has_doc {
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::itemlikevisit::ItemLikeVisitor;
-use rustc_middle::middle::cstore::{DllImport, NativeLib};
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::middle::cstore::{DllCallingConvention, DllImport, NativeLib};
+use rustc_middle::ty::{List, ParamEnv, ParamEnvAnd, Ty, TyCtxt};
use rustc_session::parse::feature_err;
use rustc_session::utils::NativeLibKind;
use rustc_session::Session;
}
if lib.kind == NativeLibKind::RawDylib {
- match abi {
- Abi::C { .. } => (),
- Abi::Cdecl => (),
- _ => {
- if sess.target.arch == "x86" {
- sess.span_fatal(
- it.span,
- r#"`#[link(kind = "raw-dylib")]` only supports C and Cdecl ABIs"#,
- );
- }
- }
- };
lib.dll_imports.extend(
foreign_mod_items
.iter()
- .map(|child_item| DllImport { name: child_item.ident.name, ordinal: None }),
+ .map(|child_item| self.build_dll_import(abi, child_item)),
);
}
}
}
}
+
+ fn i686_arg_list_size(&self, item: &hir::ForeignItemRef<'_>) -> usize {
+ let argument_types: &List<Ty<'_>> = self.tcx.erase_late_bound_regions(
+ self.tcx
+ .type_of(item.id.def_id)
+ .fn_sig(self.tcx)
+ .inputs()
+ .map_bound(|slice| self.tcx.mk_type_list(slice.iter())),
+ );
+
+ argument_types
+ .iter()
+ .map(|ty| {
+ let layout = self
+ .tcx
+ .layout_of(ParamEnvAnd { param_env: ParamEnv::empty(), value: ty })
+ .expect("layout")
+ .layout;
+ // In both stdcall and fastcall, we always round up the argument size to the
+ // nearest multiple of 4 bytes.
+ (layout.size.bytes_usize() + 3) & !3
+ })
+ .sum()
+ }
+
+ fn build_dll_import(&self, abi: Abi, item: &hir::ForeignItemRef<'_>) -> DllImport {
+ let calling_convention = if self.tcx.sess.target.arch == "x86" {
+ match abi {
+ Abi::C { .. } | Abi::Cdecl => DllCallingConvention::C,
+ Abi::Stdcall { .. } | Abi::System { .. } => {
+ DllCallingConvention::Stdcall(self.i686_arg_list_size(item))
+ }
+ Abi::Fastcall => DllCallingConvention::Fastcall(self.i686_arg_list_size(item)),
+ // Vectorcall is intentionally not supported at this time.
+ _ => {
+ self.tcx.sess.span_fatal(
+ item.span,
+ r#"ABI not supported by `#[link(kind = "raw-dylib")]` on i686"#,
+ );
+ }
+ }
+ } else {
+ match abi {
+ Abi::C { .. } | Abi::Win64 | Abi::System { .. } => DllCallingConvention::C,
+ _ => {
+ self.tcx.sess.span_fatal(
+ item.span,
+ r#"ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture"#,
+ );
+ }
+ }
+ };
+ DllImport { name: item.ident.name, ordinal: None, calling_convention, span: item.span }
+ }
}
// required that their size stay the same, but we don't want to change
// it inadvertently. This assert just ensures we're aware of any change.
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-static_assert_size!(DepNode, 17);
+static_assert_size!(DepNode, 18);
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
static_assert_size!(DepNode, 24);
pub dll_imports: Vec<DllImport>,
}
-#[derive(Clone, Debug, Encodable, Decodable, HashStable)]
+#[derive(Clone, Debug, PartialEq, Eq, Encodable, Decodable, Hash, HashStable)]
pub struct DllImport {
pub name: Symbol,
pub ordinal: Option<u16>,
+ /// Calling convention for the function.
+ ///
+ /// On x86_64, this is always `DllCallingConvention::C`; on i686, it can be any
+ /// of the values, and we use `DllCallingConvention::C` to represent `"cdecl"`.
+ pub calling_convention: DllCallingConvention,
+ /// Span of import's "extern" declaration; used for diagnostics.
+ pub span: Span,
+}
+
+/// Calling convention for a function defined in an external library.
+///
+/// The usize value, where present, indicates the size of the function's argument list
+/// in bytes.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Encodable, Decodable, Hash, HashStable)]
+pub enum DllCallingConvention {
+ C,
+ Stdcall(usize),
+ Fastcall(usize),
+ Vectorcall(usize),
}
#[derive(Clone, TyEncodable, TyDecodable, HashStable, Debug)]
desc { |tcx| "looking up const stability of `{}`", tcx.def_path_str(def_id) }
}
+ query should_inherit_track_caller(def_id: DefId) -> bool {
+ desc { |tcx| "computing should_inherit_track_caller of `{}`", tcx.def_path_str(def_id) }
+ }
+
query lookup_deprecation_entry(def_id: DefId) -> Option<DeprecationEntry> {
desc { |tcx| "checking whether `{}` is deprecated", tcx.def_path_str(def_id) }
}
/// impl Clone for i32 { ... } // Impl_3
///
/// fn foo<T: Clone>(concrete: Option<Box<i32>>, param: T, mixed: Option<T>) {
-/// // Case A: Vtable points at a specific impl. Only possible when
+/// // Case A: ImplSource points at a specific impl. Only possible when
/// // type is concretely known. If the impl itself has bounded
-/// // type parameters, Vtable will carry resolutions for those as well:
-/// concrete.clone(); // Vtable(Impl_1, [Vtable(Impl_2, [Vtable(Impl_3)])])
+/// // type parameters, ImplSource will carry resolutions for those as well:
+/// concrete.clone(); // ImpleSource(Impl_1, [ImplSource(Impl_2, [ImplSource(Impl_3)])])
///
/// // Case A: ImplSource points at a specific impl. Only possible when
/// // type is concretely known. If the impl itself has bounded
pub fn requires_caller_location(&self, tcx: TyCtxt<'_>) -> bool {
match *self {
- InstanceDef::Item(def) => {
- tcx.codegen_fn_attrs(def.did).flags.contains(CodegenFnAttrFlags::TRACK_CALLER)
+ InstanceDef::Item(ty::WithOptConstParam { did: def_id, .. })
+ | InstanceDef::Virtual(def_id, _) => {
+ tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::TRACK_CALLER)
}
_ => false,
}
def_id: DefId,
substs: SubstsRef<'tcx>,
) -> Option<Instance<'tcx>> {
- debug!("resolve(def_id={:?}, substs={:?})", def_id, substs);
+ debug!("resolve_for_vtable(def_id={:?}, substs={:?})", def_id, substs);
let fn_sig = tcx.fn_sig(def_id);
let is_vtable_shim = !fn_sig.inputs().skip_binder().is_empty()
&& fn_sig.input(0).skip_binder().is_param(0)
debug!(" => associated item with unsizeable self: Self");
Some(Instance { def: InstanceDef::VtableShim(def_id), substs })
} else {
- Instance::resolve_for_fn_ptr(tcx, param_env, def_id, substs)
+ Instance::resolve(tcx, param_env, def_id, substs).ok().flatten().map(|mut resolved| {
+ match resolved.def {
+ InstanceDef::Item(def) => {
+ // We need to generate a shim when we cannot guarantee that
+ // the caller of a trait object method will be aware of
+ // `#[track_caller]` - this ensures that the caller
+ // and callee ABI will always match.
+ //
+ // The shim is generated when all of these conditions are met:
+ //
+ // 1) The underlying method expects a caller location parameter
+ // in the ABI
+ if resolved.def.requires_caller_location(tcx)
+ // 2) The caller location parameter comes from having `#[track_caller]`
+ // on the implementation, and *not* on the trait method.
+ && !tcx.should_inherit_track_caller(def.did)
+ // If the method implementation comes from the trait definition itself
+ // (e.g. `trait Foo { #[track_caller] my_fn() { /* impl */ } }`),
+ // then we don't need to generate a shim. This check is needed because
+ // `should_inherit_track_caller` returns `false` if our method
+ // implementation comes from the trait block, and not an impl block
+ && !matches!(
+ tcx.opt_associated_item(def.did),
+ Some(ty::AssocItem {
+ container: ty::AssocItemContainer::TraitContainer(_),
+ ..
+ })
+ )
+ {
+ debug!(
+ " => vtable fn pointer created for function with #[track_caller]"
+ );
+ resolved.def = InstanceDef::ReifyShim(def.did);
+ }
+ }
+ InstanceDef::Virtual(def_id, _) => {
+ debug!(" => vtable fn pointer created for virtual call");
+ resolved.def = InstanceDef::ReifyShim(def_id);
+ }
+ _ => {}
+ }
+
+ resolved
+ })
}
}
}
}
+/// Comparing raw pointers for equality.
+/// Not currently intended to ever be allowed, even behind a feature gate: operation depends on
+/// allocation base addresses that are not known at compile-time.
#[derive(Debug)]
pub struct RawPtrComparison;
impl NonConstOp for RawPtrComparison {
}
}
+/// Casting raw pointer or function pointer to an integer.
+/// Not currently intended to ever be allowed, even behind a feature gate: operation depends on
+/// allocation base addresses that are not known at compile-time.
#[derive(Debug)]
pub struct RawPtrToIntCast;
impl NonConstOp for RawPtrToIntCast {
- fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
- Status::Unstable(sym::const_raw_ptr_to_usize_cast)
- }
-
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
- feature_err(
- &ccx.tcx.sess.parse_sess,
- sym::const_raw_ptr_to_usize_cast,
- span,
- &format!("casting pointers to integers in {}s is unstable", ccx.const_kind(),),
- )
+ let mut err = ccx
+ .tcx
+ .sess
+ .struct_span_err(span, "pointers cannot be cast to integers during const eval.");
+ err.note("at compile-time, pointers do not have an integer value");
+ err.note(
+ "avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior",
+ );
+ err
}
}
use rustc_hir::Node;
use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*;
-use rustc_middle::ty::cast::CastTy;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, TyCtxt};
use rustc_session::lint::builtin::{UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE};
pub struct UnsafetyChecker<'a, 'tcx> {
body: &'a Body<'tcx>,
body_did: LocalDefId,
- const_context: bool,
violations: Vec<UnsafetyViolation>,
source_info: SourceInfo,
tcx: TyCtxt<'tcx>,
impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
fn new(
- const_context: bool,
body: &'a Body<'tcx>,
body_did: LocalDefId,
tcx: TyCtxt<'tcx>,
Self {
body,
body_did,
- const_context,
violations: vec![],
source_info: SourceInfo::outermost(body.span),
tcx,
self.register_violations(&violations, &unsafe_blocks);
}
},
- // casting pointers to ints is unsafe in const fn because the const evaluator cannot
- // possibly know what the result of various operations like `address / 2` would be
- // pointers during const evaluation have no integral address, only an abstract one
- Rvalue::Cast(CastKind::Misc, ref operand, cast_ty)
- if self.const_context && self.tcx.features().const_raw_ptr_to_usize_cast =>
- {
- let operand_ty = operand.ty(self.body, self.tcx);
- let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast");
- let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
- match (cast_in, cast_out) {
- (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) => {
- self.require_unsafe(
- UnsafetyViolationKind::General,
- UnsafetyViolationDetails::CastOfPointerToInt,
- );
- }
- _ => {}
- }
- }
_ => {}
}
self.super_rvalue(rvalue, location);
let param_env = tcx.param_env(def.did);
- let id = tcx.hir().local_def_id_to_hir_id(def.did);
- let const_context = match tcx.hir().body_owner_kind(id) {
- hir::BodyOwnerKind::Closure => false,
- hir::BodyOwnerKind::Fn => tcx.is_const_fn_raw(def.did.to_def_id()),
- hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => true,
- };
- let mut checker = UnsafetyChecker::new(const_context, body, def.did, tcx, param_env);
+ let mut checker = UnsafetyChecker::new(body, def.did, tcx, param_env);
checker.visit_body(&body);
check_unused_unsafe(tcx, def.did, &checker.used_unsafe, &mut checker.inherited_blocks);
&self,
callsite: &CallSite<'tcx>,
callee_attrs: &CodegenFnAttrs,
- ) -> Result<(), &'satic str> {
+ ) -> Result<(), &'static str> {
if let InlineAttr::Never = callee_attrs.inline {
return Err("never inline hint");
}
/// The `#[target_feature]` attributes of the body. Used for checking
/// calls to functions with `#[target_feature]` (RFC 2396).
body_target_features: &'tcx Vec<Symbol>,
- is_const: bool,
+ in_possible_lhs_union_assign: bool,
+ in_union_destructure: bool,
}
impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
}
}
+ fn visit_pat(&mut self, pat: &Pat<'tcx>) {
+ use PatKind::*;
+
+ if self.in_union_destructure {
+ match *pat.kind {
+ // binding to a variable allows getting stuff out of variable
+ Binding { .. }
+ // match is conditional on having this value
+ | Constant { .. }
+ | Variant { .. }
+ | Leaf { .. }
+ | Deref { .. }
+ | Range { .. }
+ | Slice { .. }
+ | Array { .. } => {
+ self.requires_unsafe(pat.span, AccessToUnionField);
+ return; // don't walk pattern
+ }
+ // wildcard doesn't take anything
+ Wild |
+ // these just wrap other patterns
+ Or { .. } |
+ AscribeUserType { .. } => {}
+ }
+ };
+
+ if let ty::Adt(adt_def, _) = pat.ty.kind() {
+ // check for extracting values from union via destructuring
+ if adt_def.is_union() {
+ match *pat.kind {
+ // assigning the whole union is okay
+ // let x = Union { ... };
+ // let y = x; // safe
+ Binding { .. } |
+ // binding to wildcard is okay since that never reads anything and stops double errors
+ // with implict wildcard branches from `if let`s
+ Wild |
+ // doesn't have any effect on semantics
+ AscribeUserType { .. } |
+ // creating a union literal
+ Constant { .. } => {},
+ Leaf { .. } | Or { .. } => {
+ // pattern matching with a union and not doing something like v = Union { bar: 5 }
+ self.in_union_destructure = true;
+ visit::walk_pat(self, pat);
+ self.in_union_destructure = false;
+ return; // don't walk pattern
+ }
+ Variant { .. } | Deref { .. } | Range { .. } | Slice { .. } | Array { .. } =>
+ unreachable!("impossible union destructuring type"),
+ }
+ }
+ }
+
+ visit::walk_pat(self, pat);
+ }
+
fn visit_expr(&mut self, expr: &Expr<'tcx>) {
+ // could we be in a the LHS of an assignment of a union?
+ match expr.kind {
+ ExprKind::Field { .. }
+ | ExprKind::VarRef { .. }
+ | ExprKind::UpvarRef { .. }
+ | ExprKind::Scope { .. }
+ | ExprKind::Cast { .. } => {}
+
+ ExprKind::AddressOf { .. }
+ | ExprKind::Adt { .. }
+ | ExprKind::Array { .. }
+ | ExprKind::Binary { .. }
+ | ExprKind::Block { .. }
+ | ExprKind::Borrow { .. }
+ | ExprKind::Literal { .. }
+ | ExprKind::ConstBlock { .. }
+ | ExprKind::Deref { .. }
+ | ExprKind::Index { .. }
+ | ExprKind::NeverToAny { .. }
+ | ExprKind::PlaceTypeAscription { .. }
+ | ExprKind::ValueTypeAscription { .. }
+ | ExprKind::Pointer { .. }
+ | ExprKind::Repeat { .. }
+ | ExprKind::StaticRef { .. }
+ | ExprKind::ThreadLocalRef { .. }
+ | ExprKind::Tuple { .. }
+ | ExprKind::Unary { .. }
+ | ExprKind::Call { .. }
+ | ExprKind::Assign { .. }
+ | ExprKind::AssignOp { .. }
+ | ExprKind::Break { .. }
+ | ExprKind::Closure { .. }
+ | ExprKind::Continue { .. }
+ | ExprKind::Return { .. }
+ | ExprKind::Yield { .. }
+ | ExprKind::Loop { .. }
+ | ExprKind::Match { .. }
+ | ExprKind::Box { .. }
+ | ExprKind::If { .. }
+ | ExprKind::InlineAsm { .. }
+ | ExprKind::LlvmInlineAsm { .. }
+ | ExprKind::LogicalOp { .. }
+ | ExprKind::Use { .. } => self.in_possible_lhs_union_assign = false,
+ };
match expr.kind {
ExprKind::Scope { value, lint_level: LintLevel::Explicit(hir_id), region_scope: _ } => {
let prev_id = self.hir_context;
self.hir_context = hir_id;
self.visit_expr(&self.thir[value]);
self.hir_context = prev_id;
- return;
+ return; // don't visit the whole expression
}
ExprKind::Call { fun, ty: _, args: _, from_hir_call: _, fn_span: _ } => {
if self.thir[fun].ty.fn_sig(self.tcx).unsafety() == hir::Unsafety::Unsafe {
(Bound::Unbounded, Bound::Unbounded) => {}
_ => self.requires_unsafe(expr.span, InitializingTypeWith),
},
- ExprKind::Cast { source } => {
- let source = &self.thir[source];
- if self.tcx.features().const_raw_ptr_to_usize_cast
- && self.is_const
- && (source.ty.is_unsafe_ptr() || source.ty.is_fn_ptr())
- && expr.ty.is_integral()
- {
- self.requires_unsafe(expr.span, CastOfPointerToInt);
- }
- }
ExprKind::Closure {
closure_id,
substs: _,
// Unsafe blocks can be used in closures, make sure to take it into account
self.safety_context = closure_visitor.safety_context;
}
+ ExprKind::Field { lhs, .. } => {
+ // assigning to union field is okay for AccessToUnionField
+ if let ty::Adt(adt_def, _) = &self.thir[lhs].ty.kind() {
+ if adt_def.is_union() {
+ if self.in_possible_lhs_union_assign {
+ // FIXME: trigger AssignToDroppingUnionField unsafety if needed
+ } else {
+ self.requires_unsafe(expr.span, AccessToUnionField);
+ }
+ }
+ }
+ }
+ // don't have any special handling for AssignOp since it causes a read *and* write to lhs
+ ExprKind::Assign { lhs, rhs } => {
+ // assigning to a union is safe, check here so it doesn't get treated as a read later
+ self.in_possible_lhs_union_assign = true;
+ visit::walk_expr(self, &self.thir()[lhs]);
+ self.in_possible_lhs_union_assign = false;
+ visit::walk_expr(self, &self.thir()[rhs]);
+ return; // don't visit the whole expression
+ }
_ => {}
}
-
visit::walk_expr(self, expr);
}
}
CallToUnsafeFunction,
UseOfInlineAssembly,
InitializingTypeWith,
- CastOfPointerToInt,
UseOfMutableStatic,
UseOfExternStatic,
DerefOfRawPointer,
#[allow(dead_code)] // FIXME
AssignToDroppingUnionField,
- #[allow(dead_code)] // FIXME
AccessToUnionField,
#[allow(dead_code)] // FIXME
MutationOfLayoutConstrainedField,
"initializing a layout restricted type's field with a value outside the valid \
range is undefined behavior",
),
- CastOfPointerToInt => {
- ("cast of pointer to int", "casting pointers to integers in constants")
- }
UseOfMutableStatic => (
"use of mutable static",
"mutable statics can be mutated by multiple threads: aliasing violations or data \
let body_target_features = &tcx.codegen_fn_attrs(def.did).target_features;
let safety_context =
if body_unsafety.is_unsafe() { SafetyContext::UnsafeFn } else { SafetyContext::Safe };
- let is_const = match tcx.hir().body_owner_kind(hir_id) {
- hir::BodyOwnerKind::Closure => false,
- hir::BodyOwnerKind::Fn => tcx.is_const_fn_raw(def.did.to_def_id()),
- hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => true,
- };
let mut visitor = UnsafetyVisitor {
tcx,
thir,
hir_context: hir_id,
body_unsafety,
body_target_features,
- is_const,
+ in_possible_lhs_union_assign: false,
+ in_union_destructure: false,
};
visitor.visit_expr(&thir[expr]);
}
}
pub fn walk_stmt<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, stmt: &Stmt<'tcx>) {
- match stmt.kind {
- StmtKind::Expr { expr, scope: _ } => visitor.visit_expr(&visitor.thir()[expr]),
+ match &stmt.kind {
+ StmtKind::Expr { expr, scope: _ } => visitor.visit_expr(&visitor.thir()[*expr]),
StmtKind::Let {
initializer,
remainder_scope: _,
lint_level: _,
} => {
if let Some(init) = initializer {
- visitor.visit_expr(&visitor.thir()[init]);
+ visitor.visit_expr(&visitor.thir()[*init]);
}
visitor.visit_pat(pattern);
}
}
}
GenericParamDefKind::Const { .. } => {
- // FIXME(const_generics_defaults): Figure out if this
- // is the behavior we want, see the comment further below.
if is_our_default(¶m) {
+ // FIXME(const_generics_defaults): This
+ // is incorrect when dealing with unused substs, for example
+ // for `struct Foo<const N: usize, const M: usize = { 1 - 2 }>`
+ // we should eagerly error.
let default_ct = tcx.const_param_default(param.def_id);
- fcx.register_wf_obligation(
- default_ct.into(),
- tcx.def_span(param.def_id),
- ObligationCauseCode::MiscObligation,
- );
+ if !default_ct.needs_subst() {
+ fcx.register_wf_obligation(
+ default_ct.into(),
+ tcx.def_span(param.def_id),
+ ObligationCauseCode::MiscObligation,
+ );
+ }
}
}
// Doesn't have defaults.
tcx.mk_param_from_def(param)
}
GenericParamDefKind::Const { .. } => {
- // FIXME(const_generics_defaults): I(@lcnr) feel like always
- // using the const parameter is the right choice here, even
- // if it needs substs.
- //
- // Before stabilizing this we probably want to get some tests
- // where this makes a difference and figure out what's the exact
- // behavior we want here.
-
// If the param has a default, ...
if is_our_default(param) {
let default_ct = tcx.const_param_default(param.def_id);
generator_kind,
codegen_fn_attrs,
collect_mod_item_types,
+ should_inherit_track_caller,
..*providers
};
}
));
}
}
+
+ fn visit_const_param_default(&mut self, _param: HirId, _ct: &'tcx hir::AnonConst) {
+ // Do not look into const param defaults,
+ // these get checked when they are actually instantiated.
+ //
+ // We do not want the following to error:
+ //
+ // struct Foo<const N: usize, const M: usize = { N + 1 }>;
+ // struct Bar<const N: usize>(Foo<N, 3>);
+ }
}
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let attrs = tcx.get_attrs(id);
let mut codegen_fn_attrs = CodegenFnAttrs::new();
- if should_inherit_track_caller(tcx, id) {
+ if tcx.should_inherit_track_caller(id) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
}
#![stable(feature = "process_extensions", since = "1.2.0")]
+use crate::ffi::OsStr;
use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
use crate::process;
use crate::sealed::Sealed;
/// [2]: <https://msdn.microsoft.com/en-us/library/17w5ykft.aspx>
#[unstable(feature = "windows_process_extensions_force_quotes", issue = "82227")]
fn force_quotes(&mut self, enabled: bool) -> &mut process::Command;
+
+ /// Append literal text to the command line without any quoting or escaping.
+ ///
+ /// This is useful for passing arguments to `cmd.exe /c`, which doesn't follow
+ /// `CommandLineToArgvW` escaping rules.
+ #[unstable(feature = "windows_process_extensions_raw_arg", issue = "29494")]
+ fn raw_arg<S: AsRef<OsStr>>(&mut self, text_to_append_as_is: S) -> &mut process::Command;
}
#[stable(feature = "windows_process_extensions", since = "1.16.0")]
self.as_inner_mut().force_quotes(enabled);
self
}
+
+ fn raw_arg<S: AsRef<OsStr>>(&mut self, raw_text: S) -> &mut process::Command {
+ self.as_inner_mut().raw_arg(raw_text.as_ref());
+ self
+ }
}
pub struct Command {
program: OsString,
- args: Vec<OsString>,
+ args: Vec<Arg>,
env: CommandEnv,
cwd: Option<OsString>,
flags: u32,
pub stderr: Option<AnonPipe>,
}
+#[derive(Debug)]
+enum Arg {
+ /// Add quotes (if needed)
+ Regular(OsString),
+ /// Append raw string without quoting
+ Raw(OsString),
+}
+
impl Command {
pub fn new(program: &OsStr) -> Command {
Command {
}
pub fn arg(&mut self, arg: &OsStr) {
- self.args.push(arg.to_os_string())
+ self.args.push(Arg::Regular(arg.to_os_string()))
}
pub fn env_mut(&mut self) -> &mut CommandEnv {
&mut self.env
self.force_quotes_enabled = enabled;
}
+ pub fn raw_arg(&mut self, command_str_to_append: &OsStr) {
+ self.args.push(Arg::Raw(command_str_to_append.to_os_string()))
+ }
+
pub fn get_program(&self) -> &OsStr {
&self.program
}
impl fmt::Debug for Command {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "{:?}", self.program)?;
+ self.program.fmt(f)?;
for arg in &self.args {
- write!(f, " {:?}", arg)?;
+ f.write_str(" ")?;
+ match arg {
+ Arg::Regular(s) => s.fmt(f),
+ Arg::Raw(s) => f.write_str(&s.to_string_lossy()),
+ }?;
}
Ok(())
}
}
}
+enum Quote {
+ // Every arg is quoted
+ Always,
+ // Whitespace and empty args are quoted
+ Auto,
+ // Arg appended without any changes (#29494)
+ Never,
+}
+
// Produces a wide string *without terminating null*; returns an error if
// `prog` or any of the `args` contain a nul.
-fn make_command_line(prog: &OsStr, args: &[OsString], force_quotes: bool) -> io::Result<Vec<u16>> {
+fn make_command_line(prog: &OsStr, args: &[Arg], force_quotes: bool) -> io::Result<Vec<u16>> {
// Encode the command and arguments in a command line string such
// that the spawned process may recover them using CommandLineToArgvW.
let mut cmd: Vec<u16> = Vec::new();
// Always quote the program name so CreateProcess doesn't interpret args as
// part of the name if the binary wasn't found first time.
- append_arg(&mut cmd, prog, true)?;
+ append_arg(&mut cmd, prog, Quote::Always)?;
for arg in args {
cmd.push(' ' as u16);
- append_arg(&mut cmd, arg, force_quotes)?;
+ let (arg, quote) = match arg {
+ Arg::Regular(arg) => (arg, if force_quotes { Quote::Always } else { Quote::Auto }),
+ Arg::Raw(arg) => (arg, Quote::Never),
+ };
+ append_arg(&mut cmd, arg, quote)?;
}
return Ok(cmd);
- fn append_arg(cmd: &mut Vec<u16>, arg: &OsStr, force_quotes: bool) -> io::Result<()> {
+ fn append_arg(cmd: &mut Vec<u16>, arg: &OsStr, quote: Quote) -> io::Result<()> {
// If an argument has 0 characters then we need to quote it to ensure
// that it actually gets passed through on the command line or otherwise
// it will be dropped entirely when parsed on the other end.
ensure_no_nuls(arg)?;
let arg_bytes = &arg.as_inner().inner.as_inner();
- let quote = force_quotes
- || arg_bytes.iter().any(|c| *c == b' ' || *c == b'\t')
- || arg_bytes.is_empty();
+ let (quote, escape) = match quote {
+ Quote::Always => (true, true),
+ Quote::Auto => {
+ (arg_bytes.iter().any(|c| *c == b' ' || *c == b'\t') || arg_bytes.is_empty(), true)
+ }
+ Quote::Never => (false, false),
+ };
if quote {
cmd.push('"' as u16);
}
let mut backslashes: usize = 0;
for x in arg.encode_wide() {
- if x == '\\' as u16 {
- backslashes += 1;
- } else {
- if x == '"' as u16 {
- // Add n+1 backslashes to total 2n+1 before internal '"'.
- cmd.extend((0..=backslashes).map(|_| '\\' as u16));
+ if escape {
+ if x == '\\' as u16 {
+ backslashes += 1;
+ } else {
+ if x == '"' as u16 {
+ // Add n+1 backslashes to total 2n+1 before internal '"'.
+ cmd.extend((0..=backslashes).map(|_| '\\' as u16));
+ }
+ backslashes = 0;
}
- backslashes = 0;
}
cmd.push(x);
}
}
pub struct CommandArgs<'a> {
- iter: crate::slice::Iter<'a, OsString>,
+ iter: crate::slice::Iter<'a, Arg>,
}
impl<'a> Iterator for CommandArgs<'a> {
type Item = &'a OsStr;
fn next(&mut self) -> Option<&'a OsStr> {
- self.iter.next().map(|s| s.as_ref())
+ self.iter.next().map(|arg| match arg {
+ Arg::Regular(s) | Arg::Raw(s) => s.as_ref(),
+ })
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
use super::make_command_line;
+use super::Arg;
use crate::env;
use crate::ffi::{OsStr, OsString};
use crate::process::Command;
+#[test]
+fn test_raw_args() {
+ let command_line = &make_command_line(
+ OsStr::new("quoted exe"),
+ &[
+ Arg::Regular(OsString::from("quote me")),
+ Arg::Raw(OsString::from("quote me *not*")),
+ Arg::Raw(OsString::from("\t\\")),
+ Arg::Raw(OsString::from("internal \\\"backslash-\"quote")),
+ Arg::Regular(OsString::from("optional-quotes")),
+ ],
+ false,
+ )
+ .unwrap();
+ assert_eq!(
+ String::from_utf16(command_line).unwrap(),
+ "\"quoted exe\" \"quote me\" quote me *not* \t\\ internal \\\"backslash-\"quote optional-quotes"
+ );
+}
+
#[test]
fn test_make_command_line() {
fn test_wrapper(prog: &str, args: &[&str], force_quotes: bool) -> String {
let command_line = &make_command_line(
OsStr::new(prog),
- &args.iter().map(|a| OsString::from(a)).collect::<Vec<OsString>>(),
+ &args.iter().map(|a| Arg::Regular(OsString::from(a))).collect::<Vec<_>>(),
force_quotes,
)
.unwrap();
assert_eq!(test_wrapper("prog", &["aaa", "bbb", "ccc"], false), "\"prog\" aaa bbb ccc");
+ assert_eq!(test_wrapper("prog", &[r"C:\"], false), r#""prog" C:\"#);
+ assert_eq!(test_wrapper("prog", &[r"2slashes\\"], false), r#""prog" 2slashes\\"#);
+ assert_eq!(test_wrapper("prog", &[r" C:\"], false), r#""prog" " C:\\""#);
+ assert_eq!(test_wrapper("prog", &[r" 2slashes\\"], false), r#""prog" " 2slashes\\\\""#);
+
assert_eq!(
test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa"], false),
"\"C:\\Program Files\\blah\\blah.exe\" aaa"
static mut COUNTER: u64 = 1;
unsafe {
- let _guard = GUARD.lock();
+ let guard = GUARD.lock();
// If we somehow use up all our bits, panic so that we're not
// covering up subtle bugs of IDs being reused.
if COUNTER == u64::MAX {
+ drop(guard); // in case the panic handler ends up calling `ThreadId::new()`, avoid reentrant lock acquire.
panic!("failed to generate unique thread ID: bitspace exhausted");
}
--- /dev/null
+# Test the behavior of #[link(.., kind = "raw-dylib")] with alternative calling conventions.
+
+# only-i686-pc-windows-msvc
+
+-include ../../run-make-fulldeps/tools.mk
+
+all:
+ $(call COMPILE_OBJ,"$(TMPDIR)"/extern.obj,extern.c)
+ $(CC) "$(TMPDIR)"/extern.obj -link -dll -out:"$(TMPDIR)"/extern.dll
+ $(RUSTC) --crate-type lib --crate-name raw_dylib_alt_calling_convention_test lib.rs
+ $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
+ "$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt
+
+ifdef RUSTC_BLESS_TEST
+ cp "$(TMPDIR)"/output.txt output.txt
+else
+ $(DIFF) output.txt "$(TMPDIR)"/output.txt
+endif
--- /dev/null
+extern crate raw_dylib_alt_calling_convention_test;
+
+fn main() {
+ raw_dylib_alt_calling_convention_test::library_function();
+}
--- /dev/null
+#include <stdio.h>
+#include <stdint.h>
+
+struct S {
+ uint8_t x;
+ int32_t y;
+};
+
+struct S2 {
+ int32_t x;
+ uint8_t y;
+};
+
+struct S3 {
+ uint8_t x[5];
+};
+
+__declspec(dllexport) void __stdcall stdcall_fn_1(int i) {
+ printf("stdcall_fn_1(%d)\n", i);
+ fflush(stdout);
+}
+
+__declspec(dllexport) void __stdcall stdcall_fn_2(uint8_t i, float f) {
+ printf("stdcall_fn_2(%d, %.1f)\n", i, f);
+ fflush(stdout);
+}
+
+__declspec(dllexport) void __stdcall stdcall_fn_3(double d) {
+ printf("stdcall_fn_3(%.1f)\n", d);
+ fflush(stdout);
+}
+
+__declspec(dllexport) void __stdcall stdcall_fn_4(uint8_t i, uint8_t j, float f) {
+ printf("stdcall_fn_4(%d, %d, %.1f)\n", i, j, f);
+ fflush(stdout);
+}
+
+__declspec(dllexport) void __stdcall stdcall_fn_5(struct S s, int i) {
+ printf("stdcall_fn_5(S { x: %d, y: %d }, %d)\n", s.x, s.y, i);
+ fflush(stdout);
+}
+
+// Test that stdcall support works correctly with the nullable pointer optimization.
+__declspec(dllexport) void __stdcall stdcall_fn_6(struct S* s) {
+ if (s) {
+ printf("stdcall_fn_6(S { x: %d, y: %d })\n", s->x, s->y);
+ } else {
+ printf("stdcall_fn_6(null)\n");
+ }
+ fflush(stdout);
+}
+
+__declspec(dllexport) void __stdcall stdcall_fn_7(struct S2 s, int i) {
+ printf("stdcall_fn_7(S2 { x: %d, y: %d }, %d)\n", s.x, s.y, i);
+ fflush(stdout);
+}
+
+// Verify that we compute the correct amount of space in the argument list for a 5-byte struct.
+__declspec(dllexport) void __stdcall stdcall_fn_8(struct S3 s, struct S3 t) {
+ printf("stdcall_fn_8(S3 { x: [%d, %d, %d, %d, %d] }, S3 { x: [%d, %d, %d, %d, %d] })\n",
+ s.x[0], s.x[1], s.x[2], s.x[3], s.x[4],
+ t.x[0], t.x[1], t.x[2], t.x[3], t.x[4]
+ );
+ fflush(stdout);
+}
+
+// test whether f64/double values are aligned on 4-byte or 8-byte boundaries.
+__declspec(dllexport) void __stdcall stdcall_fn_9(uint8_t x, double y) {
+ printf("stdcall_fn_9(%d, %.1f)\n", x, y);
+ fflush(stdout);
+}
+
+__declspec(dllexport) void __fastcall fastcall_fn_1(int i) {
+ printf("fastcall_fn_1(%d)\n", i);
+ fflush(stdout);
+}
+
+__declspec(dllexport) void __fastcall fastcall_fn_2(uint8_t i, float f) {
+ printf("fastcall_fn_2(%d, %.1f)\n", i, f);
+ fflush(stdout);
+}
+
+__declspec(dllexport) void __fastcall fastcall_fn_3(double d) {
+ printf("fastcall_fn_3(%.1f)\n", d);
+ fflush(stdout);
+}
+
+__declspec(dllexport) void __fastcall fastcall_fn_4(uint8_t i, uint8_t j, float f) {
+ printf("fastcall_fn_4(%d, %d, %.1f)\n", i, j, f);
+ fflush(stdout);
+}
+
+__declspec(dllexport) void __fastcall fastcall_fn_5(struct S s, int i) {
+ printf("fastcall_fn_5(S { x: %d, y: %d }, %d)\n", s.x, s.y, i);
+ fflush(stdout);
+}
+
+__declspec(dllexport) void __fastcall fastcall_fn_6(struct S* s) {
+ if (s) {
+ printf("fastcall_fn_6(S { x: %d, y: %d })\n", s->x, s->y);
+ } else {
+ printf("fastcall_fn_6(null)\n");
+ }
+ fflush(stdout);
+}
+
+__declspec(dllexport) void __fastcall fastcall_fn_7(struct S2 s, int i) {
+ printf("fastcall_fn_7(S2 { x: %d, y: %d }, %d)\n", s.x, s.y, i);
+ fflush(stdout);
+}
+
+__declspec(dllexport) void __fastcall fastcall_fn_8(struct S3 s, struct S3 t) {
+ printf("fastcall_fn_8(S3 { x: [%d, %d, %d, %d, %d] }, S3 { x: [%d, %d, %d, %d, %d] })\n",
+ s.x[0], s.x[1], s.x[2], s.x[3], s.x[4],
+ t.x[0], t.x[1], t.x[2], t.x[3], t.x[4]
+ );
+ fflush(stdout);
+}
+
+__declspec(dllexport) void __fastcall fastcall_fn_9(uint8_t x, double y) {
+ printf("fastcall_fn_9(%d, %.1f)\n", x, y);
+ fflush(stdout);
+}
--- /dev/null
+#![feature(raw_dylib)]
+
+#[repr(C)]
+#[derive(Clone)]
+struct S {
+ x: u8,
+ y: i32,
+}
+
+#[repr(C)]
+#[derive(Clone)]
+struct S2 {
+ x: i32,
+ y: u8,
+}
+
+#[repr(C)]
+#[derive(Clone)]
+struct S3 {
+ x: [u8; 5],
+}
+
+#[link(name = "extern", kind = "raw-dylib")]
+extern "stdcall" {
+ fn stdcall_fn_1(i: i32);
+ fn stdcall_fn_2(c: u8, f: f32);
+ fn stdcall_fn_3(d: f64);
+ fn stdcall_fn_4(i: u8, j: u8, f: f32);
+ fn stdcall_fn_5(a: S, b: i32);
+ fn stdcall_fn_6(a: Option<&S>);
+ fn stdcall_fn_7(a: S2, b: i32);
+ fn stdcall_fn_8(a: S3, b: S3);
+ fn stdcall_fn_9(x: u8, y: f64);
+}
+
+#[link(name = "extern", kind = "raw-dylib")]
+extern "fastcall" {
+ fn fastcall_fn_1(i: i32);
+ fn fastcall_fn_2(c: u8, f: f32);
+ fn fastcall_fn_3(d: f64);
+ fn fastcall_fn_4(i: u8, j: u8, f: f32);
+ fn fastcall_fn_5(a: S, b: i32);
+ fn fastcall_fn_6(a: Option<&S>);
+ fn fastcall_fn_7(a: S2, b: i32);
+ fn fastcall_fn_8(a: S3, b: S3);
+ fn fastcall_fn_9(x: u8, y: f64);
+}
+
+pub fn library_function() {
+ unsafe {
+ stdcall_fn_1(14);
+ stdcall_fn_2(16, 3.5);
+ stdcall_fn_3(3.5);
+ stdcall_fn_4(1, 2, 3.0);
+ stdcall_fn_5(S { x: 1, y: 2 }, 16);
+ stdcall_fn_6(Some(&S { x: 10, y: 12 }));
+ stdcall_fn_7(S2 { x: 15, y: 16 }, 3);
+ stdcall_fn_8(S3 { x: [1, 2, 3, 4, 5] }, S3 { x: [6, 7, 8, 9, 10] });
+ stdcall_fn_9(1, 3.0);
+
+ fastcall_fn_1(14);
+ fastcall_fn_2(16, 3.5);
+ fastcall_fn_3(3.5);
+ fastcall_fn_4(1, 2, 3.0);
+ fastcall_fn_5(S { x: 1, y: 2 }, 16);
+ fastcall_fn_6(Some(&S { x: 10, y: 12 }));
+ fastcall_fn_7(S2 { x: 15, y: 16 }, 3);
+ fastcall_fn_8(S3 { x: [1, 2, 3, 4, 5] }, S3 { x: [6, 7, 8, 9, 10] });
+ fastcall_fn_9(1, 3.0);
+ }
+}
--- /dev/null
+stdcall_fn_1(14)
+stdcall_fn_2(16, 3.5)
+stdcall_fn_3(3.5)
+stdcall_fn_4(1, 2, 3.0)
+stdcall_fn_5(S { x: 1, y: 2 }, 16)
+stdcall_fn_6(S { x: 10, y: 12 })
+stdcall_fn_7(S2 { x: 15, y: 16 }, 3)
+stdcall_fn_8(S3 { x: [1, 2, 3, 4, 5] }, S3 { x: [6, 7, 8, 9, 10] })
+stdcall_fn_9(1, 3.0)
+fastcall_fn_1(14)
+fastcall_fn_2(16, 3.5)
+fastcall_fn_3(3.5)
+fastcall_fn_4(1, 2, 3.0)
+fastcall_fn_5(S { x: 1, y: 2 }, 16)
+fastcall_fn_6(S { x: 10, y: 12 })
+fastcall_fn_7(S2 { x: 15, y: 16 }, 3)
+fastcall_fn_8(S3 { x: [1, 2, 3, 4, 5] }, S3 { x: [6, 7, 8, 9, 10] })
+fastcall_fn_9(1, 3.0)
--- /dev/null
+# Test the behavior of #[link(.., kind = "raw-dylib")] on windows-msvc
+
+# only-windows-msvc
+
+-include ../../run-make-fulldeps/tools.mk
+
+all:
+ $(call COMPILE_OBJ,"$(TMPDIR)"/extern_1.obj,extern_1.c)
+ $(call COMPILE_OBJ,"$(TMPDIR)"/extern_2.obj,extern_2.c)
+ $(CC) "$(TMPDIR)"/extern_1.obj -link -dll -out:"$(TMPDIR)"/extern_1.dll
+ $(CC) "$(TMPDIR)"/extern_2.obj -link -dll -out:"$(TMPDIR)"/extern_2.dll
+ $(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
+ $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
+ "$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt
+
+ifdef RUSTC_BLESS_TEST
+ cp "$(TMPDIR)"/output.txt output.txt
+else
+ $(DIFF) output.txt "$(TMPDIR)"/output.txt
+endif
--- /dev/null
+extern crate raw_dylib_test;
+
+fn main() {
+ raw_dylib_test::library_function();
+}
--- /dev/null
+#include <stdio.h>
+
+__declspec(dllexport) void extern_fn_1() {
+ printf("extern_fn_1\n");
+ fflush(stdout);
+}
+
+__declspec(dllexport) void extern_fn_2() {
+ printf("extern_fn_2; didn't get the rename\n");
+ fflush(stdout);
+}
+
+__declspec(dllexport) void extern_fn_with_long_name() {
+ printf("extern_fn_with_long_name; got the rename\n");
+ fflush(stdout);
+}
--- /dev/null
+#include <stdio.h>
+
+__declspec(dllexport) void extern_fn_3() {
+ printf("extern_fn_3\n");
+ fflush(stdout);
+}
--- /dev/null
+#![feature(raw_dylib, native_link_modifiers, native_link_modifiers_verbatim)]
+
+#[link(name = "extern_1.dll", kind = "raw-dylib", modifiers = "+verbatim")]
+extern {
+ fn extern_fn_1();
+}
+
+#[link(name = "extern_2", kind = "raw-dylib")]
+extern {
+ fn extern_fn_3();
+}
+
+pub fn library_function() {
+ #[link(name = "extern_1", kind = "raw-dylib")]
+ extern { fn extern_fn_2(); }
+
+ unsafe {
+ extern_fn_1();
+ extern_fn_2();
+ extern_fn_3();
+ }
+}
--- /dev/null
+extern_fn_1
+extern_fn_2; didn't get the rename
+extern_fn_3
+++ /dev/null
-# Test the behavior of #[link(.., kind = "raw-dylib")] on windows-msvc
-
-# only-windows
-# only-msvc
-
--include ../../run-make-fulldeps/tools.mk
-
-all:
- $(call COMPILE_OBJ,"$(TMPDIR)"/extern_1.obj,extern_1.c)
- $(call COMPILE_OBJ,"$(TMPDIR)"/extern_2.obj,extern_2.c)
- $(CC) "$(TMPDIR)"/extern_1.obj -link -dll -out:"$(TMPDIR)"/extern_1.dll
- $(CC) "$(TMPDIR)"/extern_2.obj -link -dll -out:"$(TMPDIR)"/extern_2.dll
- $(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
- $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
- "$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt
-
-ifdef RUSTC_BLESS_TEST
- cp "$(TMPDIR)"/output.txt output.txt
-else
- $(DIFF) output.txt "$(TMPDIR)"/output.txt
-endif
+++ /dev/null
-extern crate raw_dylib_test;
-
-fn main() {
- raw_dylib_test::library_function();
-}
+++ /dev/null
-#include <stdio.h>
-
-__declspec(dllexport) void extern_fn_1() {
- printf("extern_fn_1\n");
- fflush(stdout);
-}
-
-__declspec(dllexport) void extern_fn_2() {
- printf("extern_fn_2; didn't get the rename\n");
- fflush(stdout);
-}
-
-__declspec(dllexport) void extern_fn_with_long_name() {
- printf("extern_fn_with_long_name; got the rename\n");
- fflush(stdout);
-}
+++ /dev/null
-#include <stdio.h>
-
-__declspec(dllexport) void extern_fn_3() {
- printf("extern_fn_3\n");
- fflush(stdout);
-}
+++ /dev/null
-#![feature(raw_dylib, native_link_modifiers, native_link_modifiers_verbatim)]
-
-#[link(name = "extern_1.dll", kind = "raw-dylib", modifiers = "+verbatim")]
-extern {
- fn extern_fn_1();
-}
-
-#[link(name = "extern_2", kind = "raw-dylib")]
-extern {
- fn extern_fn_3();
-}
-
-pub fn library_function() {
- #[link(name = "extern_1", kind = "raw-dylib")]
- extern { fn extern_fn_2(); }
-
- unsafe {
- extern_fn_1();
- extern_fn_2();
- extern_fn_3();
- }
-}
+++ /dev/null
-extern_fn_1
-extern_fn_2; didn't get the rename
-extern_fn_3
macro_rules! pass_nonterminal {
($n:expr) => {
- #[repr(align($n))] //~ ERROR expected unsuffixed literal or identifier, found `n!()`
+ #[repr(align($n))]
+ //~^ ERROR expected unsuffixed literal or identifier, found `n!()`
+ //~| ERROR incorrect `repr(align)` attribute format
struct S;
};
}
|
= note: this error originates in the macro `pass_nonterminal` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: aborting due to previous error
+error[E0693]: incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses
+ --> $DIR/nonterminal-expansion.rs:5:16
+ |
+LL | #[repr(align($n))]
+ | ^^^^^^^^^
+...
+LL | pass_nonterminal!(n!());
+ | ------------------------ in this macro invocation
+ |
+ = note: this error originates in the macro `pass_nonterminal` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+For more information about this error, try `rustc --explain E0693`.
+++ /dev/null
-error[E0133]: cast of pointer to int is unsafe and requires unsafe function or block
- --> $DIR/cast-ptr-to-int-const.rs:10:9
- |
-LL | &Y as *const u32 as usize
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ cast of pointer to int
- |
- = note: casting pointers to integers in constants
-
-error[E0133]: cast of pointer to int is unsafe and requires unsafe function or block
- --> $DIR/cast-ptr-to-int-const.rs:17:5
- |
-LL | &0 as *const i32 as usize
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ cast of pointer to int
- |
- = note: casting pointers to integers in constants
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0133`.
+++ /dev/null
-// revisions: mir thir
-// [thir]compile-flags: -Z thir-unsafeck
-
-#![feature(const_raw_ptr_to_usize_cast)]
-
-fn main() {
- const Y: u32 = 0;
- // Cast in `const` without `unsafe` block
- const SAFE: usize = {
- &Y as *const u32 as usize
- //~^ ERROR cast of pointer to int is unsafe and requires unsafe
- };
-}
-
-// Cast in `const fn` without `unsafe` block
-const fn test() -> usize {
- &0 as *const i32 as usize
- //~^ ERROR cast of pointer to int is unsafe and requires unsafe
-}
+++ /dev/null
-error[E0133]: cast of pointer to int is unsafe and requires unsafe function or block
- --> $DIR/cast-ptr-to-int-const.rs:10:9
- |
-LL | &Y as *const u32 as usize
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ cast of pointer to int
- |
- = note: casting pointers to integers in constants
-
-error[E0133]: cast of pointer to int is unsafe and requires unsafe function or block
- --> $DIR/cast-ptr-to-int-const.rs:17:5
- |
-LL | &0 as *const i32 as usize
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ cast of pointer to int
- |
- = note: casting pointers to integers in constants
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0133`.
+++ /dev/null
-fn main() {
- const X: usize = unsafe {
- main as usize //~ ERROR casting pointers to integers in constants is unstable
- };
- const Y: u32 = 0;
- const Z: usize = unsafe {
- &Y as *const u32 as usize //~ ERROR is unstable
- };
-}
-
-const fn test() -> usize {
- &0 as *const i32 as usize //~ ERROR is unstable
-}
+++ /dev/null
-error[E0658]: casting pointers to integers in constants is unstable
- --> $DIR/feature-gate-const_raw_ptr_to_usize_cast.rs:3:9
- |
-LL | main as usize
- | ^^^^^^^^^^^^^
- |
- = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
- = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
-
-error[E0658]: casting pointers to integers in constants is unstable
- --> $DIR/feature-gate-const_raw_ptr_to_usize_cast.rs:7:9
- |
-LL | &Y as *const u32 as usize
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
- = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
-
-error[E0658]: casting pointers to integers in constant functions is unstable
- --> $DIR/feature-gate-const_raw_ptr_to_usize_cast.rs:12:5
- |
-LL | &0 as *const i32 as usize
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
- = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// check-pass
+#![feature(const_generics, const_evaluatable_checked, const_generics_defaults)]
+#![allow(incomplete_features)]
+struct Foo<const N: usize, const M: usize = { N + 1 }>;
+struct Bar<const N: usize>(Foo<N, 3>);
+fn main() {}
+++ /dev/null
-error: constant expression depends on a generic parameter
- --> $DIR/complex-generic-default-expr.rs:6:34
- |
-LL | struct Foo<const N: usize, const M: usize = { N + 1 }>;
- | ^
- |
- = note: this may fail depending on what value the parameter takes
-
-error: constant expression depends on a generic parameter
- --> $DIR/complex-generic-default-expr.rs:10:21
- |
-LL | struct Bar<T, const TYPE_SIZE: usize = { std::mem::size_of::<T>() }>(T);
- | ^^^^^^^^^
- |
- = note: this may fail depending on what value the parameter takes
-
-error: aborting due to 2 previous errors
-
error: generic parameters may not be used in const operations
- --> $DIR/complex-generic-default-expr.rs:6:47
+ --> $DIR/complex-generic-default-expr.rs:7:47
|
LL | struct Foo<const N: usize, const M: usize = { N + 1 }>;
| ^ cannot perform const operation using `N`
// revisions: full min
+//[full] check-pass
#![cfg_attr(full, feature(const_generics))]
#![feature(const_generics_defaults)]
#![allow(incomplete_features)]
struct Foo<const N: usize, const M: usize = { N + 1 }>;
-//[full]~^ ERROR constant expression depends on a generic parameter
-//[min]~^^ ERROR generic parameters may not be used in const operations
+//[min]~^ ERROR generic parameters may not be used in const operations
struct Bar<T, const TYPE_SIZE: usize = { std::mem::size_of::<T>() }>(T);
-//[full]~^ ERROR constant expression depends on a generic parameter
-//[min]~^^ ERROR generic parameters may not be used in const operations
+//[min]~^ ERROR generic parameters may not be used in const operations
fn main() {}
+++ /dev/null
-#![feature(const_raw_ptr_to_usize_cast)]
-
-fn main() {
- const OK: usize = unsafe { 0 as *const i32 as usize };
-
- const _ERROR: usize = unsafe { &0 as *const i32 as usize };
- //~^ ERROR [const_err]
- //~| NOTE cannot cast pointer to integer because it was not created by cast from integer
- //~| NOTE
- //~| NOTE `#[deny(const_err)]` on by default
- //~| WARN this was previously accepted by the compiler but is being phased out
- //~| NOTE see issue #71800
-}
+++ /dev/null
-error: any use of this value will cause an error
- --> $DIR/ptr_to_usize_cast.rs:6:36
- |
-LL | const _ERROR: usize = unsafe { &0 as *const i32 as usize };
- | -------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^---
- | |
- | cannot cast pointer to integer because it was not created by cast from integer
- |
- = note: `#[deny(const_err)]` on by default
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
-
-error: aborting due to previous error
-
-#![feature(const_raw_ptr_to_usize_cast, const_raw_ptr_deref)]
+#![feature(const_raw_ptr_deref)]
fn main() {}
-// unconst and fine
-const Y: usize = unsafe { 42usize as *const i32 as usize + 1 };
-// unconst and bad, will thus error in miri
-const Y2: usize = unsafe { &1 as *const i32 as usize + 1 }; //~ ERROR any use of this
-//~| WARN this was previously accepted by the compiler but is being phased out
-// unconst and fine
+// fine
const Z: i32 = unsafe { *(&1 as *const i32) };
-// unconst and bad, will thus error in miri
+
+// bad, will thus error in miri
const Z2: i32 = unsafe { *(42 as *const i32) }; //~ ERROR any use of this value will cause
//~| WARN this was previously accepted by the compiler but is being phased out
const Z3: i32 = unsafe { *(44 as *const i32) }; //~ ERROR any use of this value will cause
error: any use of this value will cause an error
- --> $DIR/const_raw_ptr_ops2.rs:8:28
- |
-LL | const Y2: usize = unsafe { &1 as *const i32 as usize + 1 };
- | ---------------------------^^^^^^^^^^^^^^^^^^^^^^^^^-------
- | |
- | cannot cast pointer to integer because it was not created by cast from integer
- |
- = note: `#[deny(const_err)]` on by default
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
-
-error: any use of this value will cause an error
- --> $DIR/const_raw_ptr_ops2.rs:13:26
+ --> $DIR/const_raw_ptr_ops2.rs:9:26
|
LL | const Z2: i32 = unsafe { *(42 as *const i32) };
| -------------------------^^^^^^^^^^^^^^^^^^^---
| |
| unable to turn bytes into a pointer
|
+ = note: `#[deny(const_err)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
error: any use of this value will cause an error
- --> $DIR/const_raw_ptr_ops2.rs:15:26
+ --> $DIR/const_raw_ptr_ops2.rs:11:26
|
LL | const Z3: i32 = unsafe { *(44 as *const i32) };
| -------------------------^^^^^^^^^^^^^^^^^^^---
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
+++ /dev/null
-fn main() {
- [(); { &loop { break } as *const _ as usize } ];
- //~^ ERROR casting pointers to integers in constants is unstable
-}
+++ /dev/null
-error[E0658]: casting pointers to integers in constants is unstable
- --> $DIR/issue-52442.rs:2:13
- |
-LL | [(); { &loop { break } as *const _ as usize } ];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
- = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
// bytes.
let _: [u8; 0] = [4; {
match &1 as *const i32 as usize {
- //~^ ERROR casting pointers to integers in constants
+ //~^ ERROR pointers cannot be cast to integers during const eval
0 => 42,
n => n,
}
-error[E0658]: casting pointers to integers in constants is unstable
+error: pointers cannot be cast to integers during const eval.
--> $DIR/match-test-ptr-null.rs:6:15
|
LL | match &1 as *const i32 as usize {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
- = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
+ = note: at compile-time, pointers do not have an integer value
+ = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0658`.
-#![feature(const_raw_ptr_to_usize_cast, const_raw_ptr_deref)]
+#![feature(const_raw_ptr_deref)]
fn main() {
let x: &'static bool = &(42 as *const i32 == 43 as *const i32);
const unsafe extern "C" fn use_float() { 1.0 + 1.0; }
//~^ ERROR floating point arithmetic
const extern "C" fn ptr_cast(val: *const u8) { val as usize; }
-//~^ ERROR casting pointers to integers
+//~^ ERROR pointers cannot be cast to integers
fn main() {}
= note: see issue #57241 <https://github.com/rust-lang/rust/issues/57241> for more information
= help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable
-error[E0658]: casting pointers to integers in constant functions is unstable
+error: pointers cannot be cast to integers during const eval.
--> $DIR/const-extern-fn-min-const-fn.rs:9:48
|
LL | const extern "C" fn ptr_cast(val: *const u8) { val as usize; }
| ^^^^^^^^^^^^
|
- = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
- = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
+ = note: at compile-time, pointers do not have an integer value
+ = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
error: aborting due to 4 previous errors
static X: usize = unsafe { core::ptr::null::<usize>() as usize };
-//~^ ERROR: casting pointers to integers in statics is unstable
+//~^ ERROR: pointers cannot be cast to integers during const eval
fn main() {
assert_eq!(X, 0);
-error[E0658]: casting pointers to integers in statics is unstable
+error: pointers cannot be cast to integers during const eval.
--> $DIR/issue-17458.rs:1:28
|
LL | static X: usize = unsafe { core::ptr::null::<usize>() as usize };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
- = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
+ = note: at compile-time, pointers do not have an integer value
+ = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0658`.
+++ /dev/null
-#![feature(const_raw_ptr_to_usize_cast)]
-
-const BAR: *mut () = ((|| 3) as fn() -> i32) as *mut ();
-pub const FOO: usize = unsafe { BAR as usize };
-//~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
-
-fn main() {}
+++ /dev/null
-error: any use of this value will cause an error
- --> $DIR/issue-51559.rs:4:33
- |
-LL | pub const FOO: usize = unsafe { BAR as usize };
- | --------------------------------^^^^^^^^^^^^---
- | |
- | cannot cast pointer to integer because it was not created by cast from integer
- |
- = note: `#[deny(const_err)]` on by default
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
-
-error: aborting due to previous error
-
fn main() {
- let _ = [0; (&0 as *const i32) as usize]; //~ ERROR casting pointers to integers in constants
+ let _ = [0; (&0 as *const i32) as usize]; //~ ERROR pointers cannot be cast to integers during const eval
}
-error[E0658]: casting pointers to integers in constants is unstable
+error: pointers cannot be cast to integers during const eval.
--> $DIR/issue-52023-array-size-pointer-cast.rs:2:17
|
LL | let _ = [0; (&0 as *const i32) as usize];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
- = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
+ = note: at compile-time, pointers do not have an integer value
+ = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0658`.
+++ /dev/null
-#![feature(const_raw_ptr_to_usize_cast)]
-
-fn main() {
- [(); &(static |x| {}) as *const _ as usize];
- //~^ ERROR: closures cannot be static
- //~| ERROR: type annotations needed
- [(); &(static || {}) as *const _ as usize];
- //~^ ERROR: closures cannot be static
- //~| ERROR evaluation of constant value failed
-}
+++ /dev/null
-error[E0697]: closures cannot be static
- --> $DIR/issue-52432.rs:4:12
- |
-LL | [(); &(static |x| {}) as *const _ as usize];
- | ^^^^^^^^^^
-
-error[E0697]: closures cannot be static
- --> $DIR/issue-52432.rs:7:12
- |
-LL | [(); &(static || {}) as *const _ as usize];
- | ^^^^^^^^^
-
-error[E0282]: type annotations needed
- --> $DIR/issue-52432.rs:4:20
- |
-LL | [(); &(static |x| {}) as *const _ as usize];
- | ^ consider giving this closure parameter a type
-
-error[E0080]: evaluation of constant value failed
- --> $DIR/issue-52432.rs:7:10
- |
-LL | [(); &(static || {}) as *const _ as usize];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot cast pointer to integer because it was not created by cast from integer
-
-error: aborting due to 4 previous errors
-
-Some errors have detailed explanations: E0080, E0282, E0697.
-For more information about an error, try `rustc --explain E0080`.
const fn foo25() -> u32 { BAR } //~ ERROR cannot refer to statics
const fn foo26() -> &'static u32 { &BAR } //~ ERROR cannot refer to statics
const fn foo30(x: *const u32) -> usize { x as usize }
-//~^ ERROR casting pointers to integers
+//~^ ERROR pointers cannot be cast to integers
const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } }
-//~^ ERROR casting pointers to integers
+//~^ ERROR pointers cannot be cast to integers
const fn foo30_2(x: *mut u32) -> usize { x as usize }
-//~^ ERROR casting pointers to integers
+//~^ ERROR pointers cannot be cast to integers
const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } }
-//~^ ERROR casting pointers to integers
+//~^ ERROR pointers cannot be cast to integers
const fn foo30_6() -> bool { let x = true; x }
const fn inc(x: &mut i32) { *x += 1 }
//~^ ERROR mutable references
|
= help: consider extracting the value of the `static` to a `const`, and referring to that
-error[E0658]: casting pointers to integers in constant functions is unstable
+error: pointers cannot be cast to integers during const eval.
--> $DIR/min_const_fn.rs:92:42
|
LL | const fn foo30(x: *const u32) -> usize { x as usize }
| ^^^^^^^^^^
|
- = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
- = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
+ = note: at compile-time, pointers do not have an integer value
+ = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
-error[E0658]: casting pointers to integers in constant functions is unstable
+error: pointers cannot be cast to integers during const eval.
--> $DIR/min_const_fn.rs:94:63
|
LL | const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } }
| ^^^^^^^^^^
|
- = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
- = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
+ = note: at compile-time, pointers do not have an integer value
+ = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
-error[E0658]: casting pointers to integers in constant functions is unstable
+error: pointers cannot be cast to integers during const eval.
--> $DIR/min_const_fn.rs:96:42
|
LL | const fn foo30_2(x: *mut u32) -> usize { x as usize }
| ^^^^^^^^^^
|
- = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
- = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
+ = note: at compile-time, pointers do not have an integer value
+ = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
-error[E0658]: casting pointers to integers in constant functions is unstable
+error: pointers cannot be cast to integers during const eval.
--> $DIR/min_const_fn.rs:98:63
|
LL | const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } }
| ^^^^^^^^^^
|
- = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
- = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
+ = note: at compile-time, pointers do not have an integer value
+ = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
error[E0658]: mutable references are not allowed in constant functions
--> $DIR/min_const_fn.rs:101:14
fn main() {
const X: u32 = 1;
- const Y: usize = unsafe { &X as *const u32 as usize }; //~ ERROR is unstable
+ const Y: usize = unsafe { &X as *const u32 as usize }; //~ ERROR pointers cannot be cast to integers
println!("{}", Y);
}
-error[E0658]: casting pointers to integers in constants is unstable
+error: pointers cannot be cast to integers during const eval.
--> $DIR/issue-18294.rs:3:31
|
LL | const Y: usize = unsafe { &X as *const u32 as usize };
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
- = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
+ = note: at compile-time, pointers do not have an integer value
+ = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0658`.
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
- --> $DIR/issue-47412.rs:21:11
+ --> $DIR/issue-47412.rs:20:11
|
LL | match *ptr {}
| ^^^^ dereference of raw pointer
union Union { unit: (), void: Void }
let u = Union { unit: () };
match u.void {}
- //[mir]~^ ERROR access to union field is unsafe
- // FIXME(thir-unsafeck): AccessToUnionField unimplemented
+ //~^ ERROR access to union field is unsafe
}
fn raw_ptr_deref() {
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/issue-47412.rs:14:11
+ |
+LL | match u.void {}
+ | ^^^^^^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
- --> $DIR/issue-47412.rs:21:11
+ --> $DIR/issue-47412.rs:20:11
|
LL | match *ptr {}
| ^^^^ dereference of raw pointer
|
= note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
-error: aborting due to previous error
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0133`.
--- /dev/null
+// Checks that undocumented private macros will not generate `missing_docs`
+// lints, but public ones will.
+//
+// This is a regression test for issue #57569
+#![deny(missing_docs)]
+#![feature(decl_macro)]
+//! Empty documentation.
+
+macro new_style_private_macro {
+ () => ()
+}
+
+pub(crate) macro new_style_crate_macro {
+ () => ()
+}
+
+macro_rules! old_style_private_macro {
+ () => ()
+}
+
+mod submodule {
+ pub macro new_style_macro_in_private_module {
+ () => ()
+ }
+
+ macro_rules! old_style_mod_private_macro {
+ () => ()
+ }
+
+ #[macro_export]
+ macro_rules! exported_to_top_level {
+ //~^ ERROR missing documentation for macro
+ () => ()
+ }
+}
+
+pub macro top_level_pub_macro {
+ //~^ ERROR missing documentation for macro
+ () => ()
+}
+
+/// Empty documentation.
+pub fn main() {}
--- /dev/null
+error: missing documentation for macro
+ --> $DIR/missing-doc-private-macro.rs:31:5
+ |
+LL | macro_rules! exported_to_top_level {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/missing-doc-private-macro.rs:5:9
+ |
+LL | #![deny(missing_docs)]
+ | ^^^^^^^^^^^^
+
+error: missing documentation for macro
+ --> $DIR/missing-doc-private-macro.rs:37:1
+ |
+LL | pub macro top_level_pub_macro {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+// Regression test for various ICEs inspired by
+// https://github.com/rust-lang/rust/issues/83921#issuecomment-814640734
+
+// compile-flags: -Zdeduplicate-diagnostics=yes
+
+#[repr(packed())]
+//~^ ERROR: incorrect `repr(packed)` attribute format
+struct S1;
+
+#[repr(align)]
+//~^ ERROR: invalid `repr(align)` attribute
+struct S2;
+
+#[repr(align(2, 4))]
+//~^ ERROR: incorrect `repr(align)` attribute format
+struct S3;
+
+#[repr(align())]
+//~^ ERROR: incorrect `repr(align)` attribute format
+struct S4;
+
+#[repr(i8())]
+//~^ ERROR: invalid representation hint
+enum E1 { A, B }
+
+#[repr(u32(42))]
+//~^ ERROR: invalid representation hint
+enum E2 { A, B }
+
+#[repr(i64 = 2)]
+//~^ ERROR: invalid representation hint
+enum E3 { A, B }
+
+fn main() {}
--- /dev/null
+error[E0552]: incorrect `repr(packed)` attribute format: `packed` takes exactly one parenthesized argument, or no parentheses at all
+ --> $DIR/issue-83921-ice.rs:6:8
+ |
+LL | #[repr(packed())]
+ | ^^^^^^^^
+
+error[E0589]: invalid `repr(align)` attribute: `align` needs an argument
+ --> $DIR/issue-83921-ice.rs:10:8
+ |
+LL | #[repr(align)]
+ | ^^^^^ help: supply an argument here: `align(...)`
+
+error[E0693]: incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses
+ --> $DIR/issue-83921-ice.rs:14:8
+ |
+LL | #[repr(align(2, 4))]
+ | ^^^^^^^^^^^
+
+error[E0693]: incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses
+ --> $DIR/issue-83921-ice.rs:18:8
+ |
+LL | #[repr(align())]
+ | ^^^^^^^
+
+error[E0552]: invalid representation hint: `i8` does not take a parenthesized argument list
+ --> $DIR/issue-83921-ice.rs:22:8
+ |
+LL | #[repr(i8())]
+ | ^^^^
+
+error[E0552]: invalid representation hint: `u32` does not take a parenthesized argument list
+ --> $DIR/issue-83921-ice.rs:26:8
+ |
+LL | #[repr(u32(42))]
+ | ^^^^^^^
+
+error[E0552]: invalid representation hint: `i64` does not take a value
+ --> $DIR/issue-83921-ice.rs:30:8
+ |
+LL | #[repr(i64 = 2)]
+ | ^^^^^^^
+
+error: aborting due to 7 previous errors
+
+Some errors have detailed explanations: E0552, E0589, E0693.
+For more information about an error, try `rustc --explain E0552`.
--- /dev/null
+error[E0565]: meta item in `repr` must be an identifier
+ --> $DIR/issue-83921-pretty.rs:10:8
+ |
+LL | #[repr("C")]
+ | ^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0565`.
--- /dev/null
+#![feature(prelude_import)]
+#![no_std]
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
+#[macro_use]
+extern crate std;
+// Regression test for #83921. A `delay_span_bug()` call was issued, but the
+// error was never reported because the pass responsible for detecting and
+// reporting the error does not run in certain modes of pretty-printing.
+
+// Make sure the error is reported if we do not just pretty-print:
+// revisions: pretty normal
+// [pretty]compile-flags: -Zunpretty=everybody_loops
+// [pretty]check-pass
+#[repr("C")]
+struct A {
+}
+
+fn main() { loop { } }
--- /dev/null
+// Regression test for #83921. A `delay_span_bug()` call was issued, but the
+// error was never reported because the pass responsible for detecting and
+// reporting the error does not run in certain modes of pretty-printing.
+
+// Make sure the error is reported if we do not just pretty-print:
+// revisions: pretty normal
+// [pretty]compile-flags: -Zunpretty=everybody_loops
+// [pretty]check-pass
+
+#[repr("C")]
+//[normal]~^ ERROR: meta item in `repr` must be an identifier [E0565]
+struct A {}
+
+fn main() {}
trait Tracked {
#[track_caller]
- fn handle(&self) {
+ fn track_caller_trait_method(&self, line: u32, col: u32) {
let location = std::panic::Location::caller();
assert_eq!(location.file(), file!());
- // we only call this via trait object, so the def site should *always* be returned
- assert_eq!(location.line(), line!() - 4);
- assert_eq!(location.column(), 5);
+ // The trait method definition is annotated with `#[track_caller]`,
+ // so caller location information will work through a method
+ // call on a trait object
+ assert_eq!(location.line(), line, "Bad line");
+ assert_eq!(location.column(), col, "Bad col");
}
+
+ fn track_caller_not_on_trait_method(&self);
+
+ #[track_caller]
+ fn track_caller_through_self(self: Box<Self>, line: u32, col: u32);
}
-impl Tracked for () {}
-impl Tracked for u8 {}
+impl Tracked for () {
+ // We have `#[track_caller]` on the implementation of the method,
+ // but not on the definition of the method in the trait. Therefore,
+ // caller location information will *not* work through a method call
+ // on a trait object. Instead, we will get the location of this method
+ #[track_caller]
+ fn track_caller_not_on_trait_method(&self) {
+ let location = std::panic::Location::caller();
+ assert_eq!(location.file(), file!());
+ assert_eq!(location.line(), line!() - 3);
+ assert_eq!(location.column(), 5);
+ }
+
+ // We don't have a `#[track_caller]` attribute, but
+ // `#[track_caller]` is present on the trait definition,
+ // so we'll still get location information
+ fn track_caller_through_self(self: Box<Self>, line: u32, col: u32) {
+ let location = std::panic::Location::caller();
+ assert_eq!(location.file(), file!());
+ // The trait method definition is annotated with `#[track_caller]`,
+ // so caller location information will work through a method
+ // call on a trait object
+ assert_eq!(location.line(), line, "Bad line");
+ assert_eq!(location.column(), col, "Bad col");
+ }
+}
fn main() {
- let tracked: &dyn Tracked = &5u8;
- tracked.handle();
+ let tracked: &dyn Tracked = &();
+ // The column is the start of 'track_caller_trait_method'
+ tracked.track_caller_trait_method(line!(), 13);
const TRACKED: &dyn Tracked = &();
- TRACKED.handle();
+ // The column is the start of 'track_caller_trait_method'
+ TRACKED.track_caller_trait_method(line!(), 13);
+ TRACKED.track_caller_not_on_trait_method();
+
+ // The column is the start of `track_caller_through_self`
+ let boxed: Box<dyn Tracked> = Box::new(());
+ boxed.track_caller_through_self(line!(), 11);
}
--- /dev/null
+// only-i686-pc-windows-msvc
+// compile-flags: --crate-type lib --emit link
+#![allow(clashing_extern_declarations)]
+#![feature(raw_dylib)]
+//~^ WARN the feature `raw_dylib` is incomplete
+#[link(name = "foo", kind = "raw-dylib")]
+extern "C" {
+ fn f(x: i32);
+ //~^ ERROR multiple definitions of external function `f` from library `foo.dll` have different calling conventions
+}
+
+pub fn lib_main() {
+ #[link(name = "foo", kind = "raw-dylib")]
+ extern "stdcall" {
+ fn f(x: i32);
+ }
+
+ unsafe { f(42); }
+}
--- /dev/null
+warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/multiple-definitions.rs:4:12
+ |
+LL | #![feature(raw_dylib)]
+ | ^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
+
+error: multiple definitions of external function `f` from library `foo.dll` have different calling conventions
+ --> $DIR/multiple-definitions.rs:8:5
+ |
+LL | fn f(x: i32);
+ | ^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
--- /dev/null
+// only-x86_64-pc-windows-msvc
+// compile-flags: --crate-type lib --emit link
+#![allow(incomplete_features)]
+#![feature(raw_dylib)]
+#[link(name = "foo", kind = "raw-dylib")]
+extern "stdcall" {
+ fn f(x: i32);
+ //~^ ERROR ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture
+}
+
+pub fn lib_main() {
+ unsafe { f(42); }
+}
--- /dev/null
+error: ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture
+ --> $DIR/unsupported-abi.rs:7:5
+ |
+LL | fn f(x: i32);
+ | ^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
#![allow(dead_code)]
use std::mem::{size_of, size_of_val, align_of, align_of_val};
// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
#![allow(path_statements)]
#![allow(dead_code)]
// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
#![allow(unused_imports)]
// aux-build:union.rs
--- /dev/null
+error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x.0`)
+ --> $DIR/union-borrow-move-parent-sibling.rs:56:13
+ |
+LL | let a = &mut u.x.0;
+ | ---------- mutable borrow occurs here (via `u.x.0`)
+LL | let b = &u.y;
+ | ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x.0` -- occurs here
+LL | use_borrow(a);
+ | - mutable borrow later used here
+ |
+ = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x.0`
+
+error[E0382]: use of moved value: `u`
+ --> $DIR/union-borrow-move-parent-sibling.rs:63:13
+ |
+LL | let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) };
+ | - move occurs because `u` has type `U`, which does not implement the `Copy` trait
+LL | let a = u.x.0;
+ | ----- value moved here
+LL | let b = u.y;
+ | ^^^ value used here after move
+
+error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x.0.0`)
+ --> $DIR/union-borrow-move-parent-sibling.rs:69:13
+ |
+LL | let a = &mut (u.x.0).0;
+ | -------------- mutable borrow occurs here (via `u.x.0.0`)
+LL | let b = &u.y;
+ | ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x.0.0` -- occurs here
+LL | use_borrow(a);
+ | - mutable borrow later used here
+ |
+ = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x.0.0`
+
+error[E0382]: use of moved value: `u`
+ --> $DIR/union-borrow-move-parent-sibling.rs:76:13
+ |
+LL | let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) };
+ | - move occurs because `u` has type `U`, which does not implement the `Copy` trait
+LL | let a = (u.x.0).0;
+ | --------- value moved here
+LL | let b = u.y;
+ | ^^^ value used here after move
+
+error[E0502]: cannot borrow `u` (via `u.x`) as immutable because it is also borrowed as mutable (via `u.y`)
+ --> $DIR/union-borrow-move-parent-sibling.rs:82:13
+ |
+LL | let a = &mut *u.y;
+ | --- mutable borrow occurs here (via `u.y`)
+LL | let b = &u.x;
+ | ^^^^ immutable borrow of `u.x` -- which overlaps with `u.y` -- occurs here
+LL | use_borrow(a);
+ | - mutable borrow later used here
+ |
+ = note: `u.x` is a field of the union `U`, so it overlaps the field `u.y`
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0382, E0502.
+For more information about an error, try `rustc --explain E0382`.
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
#![feature(untagged_unions)]
#![allow(unused)]
+++ /dev/null
-error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x.0`)
- --> $DIR/union-borrow-move-parent-sibling.rs:53:13
- |
-LL | let a = &mut u.x.0;
- | ---------- mutable borrow occurs here (via `u.x.0`)
-LL | let b = &u.y;
- | ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x.0` -- occurs here
-LL | use_borrow(a);
- | - mutable borrow later used here
- |
- = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x.0`
-
-error[E0382]: use of moved value: `u`
- --> $DIR/union-borrow-move-parent-sibling.rs:60:13
- |
-LL | let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) };
- | - move occurs because `u` has type `U`, which does not implement the `Copy` trait
-LL | let a = u.x.0;
- | ----- value moved here
-LL | let b = u.y;
- | ^^^ value used here after move
-
-error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x.0.0`)
- --> $DIR/union-borrow-move-parent-sibling.rs:66:13
- |
-LL | let a = &mut (u.x.0).0;
- | -------------- mutable borrow occurs here (via `u.x.0.0`)
-LL | let b = &u.y;
- | ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x.0.0` -- occurs here
-LL | use_borrow(a);
- | - mutable borrow later used here
- |
- = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x.0.0`
-
-error[E0382]: use of moved value: `u`
- --> $DIR/union-borrow-move-parent-sibling.rs:73:13
- |
-LL | let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) };
- | - move occurs because `u` has type `U`, which does not implement the `Copy` trait
-LL | let a = (u.x.0).0;
- | --------- value moved here
-LL | let b = u.y;
- | ^^^ value used here after move
-
-error[E0502]: cannot borrow `u` (via `u.x`) as immutable because it is also borrowed as mutable (via `u.y`)
- --> $DIR/union-borrow-move-parent-sibling.rs:79:13
- |
-LL | let a = &mut *u.y;
- | --- mutable borrow occurs here (via `u.y`)
-LL | let b = &u.x;
- | ^^^^ immutable borrow of `u.x` -- which overlaps with `u.y` -- occurs here
-LL | use_borrow(a);
- | - mutable borrow later used here
- |
- = note: `u.x` is a field of the union `U`, so it overlaps the field `u.y`
-
-error: aborting due to 5 previous errors
-
-Some errors have detailed explanations: E0382, E0502.
-For more information about an error, try `rustc --explain E0382`.
--- /dev/null
+error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x.0`)
+ --> $DIR/union-borrow-move-parent-sibling.rs:56:13
+ |
+LL | let a = &mut u.x.0;
+ | ---------- mutable borrow occurs here (via `u.x.0`)
+LL | let b = &u.y;
+ | ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x.0` -- occurs here
+LL | use_borrow(a);
+ | - mutable borrow later used here
+ |
+ = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x.0`
+
+error[E0382]: use of moved value: `u`
+ --> $DIR/union-borrow-move-parent-sibling.rs:63:13
+ |
+LL | let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) };
+ | - move occurs because `u` has type `U`, which does not implement the `Copy` trait
+LL | let a = u.x.0;
+ | ----- value moved here
+LL | let b = u.y;
+ | ^^^ value used here after move
+
+error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x.0.0`)
+ --> $DIR/union-borrow-move-parent-sibling.rs:69:13
+ |
+LL | let a = &mut (u.x.0).0;
+ | -------------- mutable borrow occurs here (via `u.x.0.0`)
+LL | let b = &u.y;
+ | ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x.0.0` -- occurs here
+LL | use_borrow(a);
+ | - mutable borrow later used here
+ |
+ = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x.0.0`
+
+error[E0382]: use of moved value: `u`
+ --> $DIR/union-borrow-move-parent-sibling.rs:76:13
+ |
+LL | let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) };
+ | - move occurs because `u` has type `U`, which does not implement the `Copy` trait
+LL | let a = (u.x.0).0;
+ | --------- value moved here
+LL | let b = u.y;
+ | ^^^ value used here after move
+
+error[E0502]: cannot borrow `u` (via `u.x`) as immutable because it is also borrowed as mutable (via `u.y`)
+ --> $DIR/union-borrow-move-parent-sibling.rs:82:13
+ |
+LL | let a = &mut *u.y;
+ | --- mutable borrow occurs here (via `u.y`)
+LL | let b = &u.x;
+ | ^^^^ immutable borrow of `u.x` -- which overlaps with `u.y` -- occurs here
+LL | use_borrow(a);
+ | - mutable borrow later used here
+ |
+ = note: `u.x` is a field of the union `U`, so it overlaps the field `u.y`
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0382, E0502.
+For more information about an error, try `rustc --explain E0382`.
// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
union U {
a: u64,
// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
type Field1 = (i32, u32);
type Field2 = f32;
// build-pass (FIXME(62277): could be check-pass?)
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
#![feature(const_fn_union)]
union U {
--- /dev/null
+error: not automatically applying `DerefMut` on `ManuallyDrop` union field
+ --> $DIR/union-deref.rs:17:14
+ |
+LL | unsafe { u.f.0 = Vec::new() };
+ | ^^^
+ |
+ = help: writing to this reference calls the destructor for the old value
+ = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
+
+error: not automatically applying `DerefMut` on `ManuallyDrop` union field
+ --> $DIR/union-deref.rs:19:19
+ |
+LL | unsafe { &mut u.f.0 };
+ | ^^^
+ |
+ = help: writing to this reference calls the destructor for the old value
+ = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
+
+error: not automatically applying `DerefMut` on `ManuallyDrop` union field
+ --> $DIR/union-deref.rs:21:14
+ |
+LL | unsafe { u.f.0.push(0) };
+ | ^^^
+ |
+ = help: writing to this reference calls the destructor for the old value
+ = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
+
+error: not automatically applying `DerefMut` on `ManuallyDrop` union field
+ --> $DIR/union-deref.rs:25:14
+ |
+LL | unsafe { u.f.0.0 = Vec::new() };
+ | ^^^^^
+ |
+ = help: writing to this reference calls the destructor for the old value
+ = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
+
+error: not automatically applying `DerefMut` on `ManuallyDrop` union field
+ --> $DIR/union-deref.rs:27:19
+ |
+LL | unsafe { &mut u.f.0.0 };
+ | ^^^^^
+ |
+ = help: writing to this reference calls the destructor for the old value
+ = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
+
+error: not automatically applying `DerefMut` on `ManuallyDrop` union field
+ --> $DIR/union-deref.rs:29:14
+ |
+LL | unsafe { u.f.0.0.push(0) };
+ | ^^^^^
+ |
+ = help: writing to this reference calls the destructor for the old value
+ = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
+
+error: aborting due to 6 previous errors
+
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
//! Test the part of RFC 2514 that is about not applying `DerefMut` coercions
//! of union fields.
#![feature(untagged_unions)]
+++ /dev/null
-error: not automatically applying `DerefMut` on `ManuallyDrop` union field
- --> $DIR/union-deref.rs:14:14
- |
-LL | unsafe { u.f.0 = Vec::new() };
- | ^^^
- |
- = help: writing to this reference calls the destructor for the old value
- = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
-
-error: not automatically applying `DerefMut` on `ManuallyDrop` union field
- --> $DIR/union-deref.rs:16:19
- |
-LL | unsafe { &mut u.f.0 };
- | ^^^
- |
- = help: writing to this reference calls the destructor for the old value
- = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
-
-error: not automatically applying `DerefMut` on `ManuallyDrop` union field
- --> $DIR/union-deref.rs:18:14
- |
-LL | unsafe { u.f.0.push(0) };
- | ^^^
- |
- = help: writing to this reference calls the destructor for the old value
- = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
-
-error: not automatically applying `DerefMut` on `ManuallyDrop` union field
- --> $DIR/union-deref.rs:22:14
- |
-LL | unsafe { u.f.0.0 = Vec::new() };
- | ^^^^^
- |
- = help: writing to this reference calls the destructor for the old value
- = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
-
-error: not automatically applying `DerefMut` on `ManuallyDrop` union field
- --> $DIR/union-deref.rs:24:19
- |
-LL | unsafe { &mut u.f.0.0 };
- | ^^^^^
- |
- = help: writing to this reference calls the destructor for the old value
- = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
-
-error: not automatically applying `DerefMut` on `ManuallyDrop` union field
- --> $DIR/union-deref.rs:26:14
- |
-LL | unsafe { u.f.0.0.push(0) };
- | ^^^^^
- |
- = help: writing to this reference calls the destructor for the old value
- = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
-
-error: aborting due to 6 previous errors
-
--- /dev/null
+error: not automatically applying `DerefMut` on `ManuallyDrop` union field
+ --> $DIR/union-deref.rs:17:14
+ |
+LL | unsafe { u.f.0 = Vec::new() };
+ | ^^^
+ |
+ = help: writing to this reference calls the destructor for the old value
+ = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
+
+error: not automatically applying `DerefMut` on `ManuallyDrop` union field
+ --> $DIR/union-deref.rs:19:19
+ |
+LL | unsafe { &mut u.f.0 };
+ | ^^^
+ |
+ = help: writing to this reference calls the destructor for the old value
+ = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
+
+error: not automatically applying `DerefMut` on `ManuallyDrop` union field
+ --> $DIR/union-deref.rs:21:14
+ |
+LL | unsafe { u.f.0.push(0) };
+ | ^^^
+ |
+ = help: writing to this reference calls the destructor for the old value
+ = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
+
+error: not automatically applying `DerefMut` on `ManuallyDrop` union field
+ --> $DIR/union-deref.rs:25:14
+ |
+LL | unsafe { u.f.0.0 = Vec::new() };
+ | ^^^^^
+ |
+ = help: writing to this reference calls the destructor for the old value
+ = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
+
+error: not automatically applying `DerefMut` on `ManuallyDrop` union field
+ --> $DIR/union-deref.rs:27:19
+ |
+LL | unsafe { &mut u.f.0.0 };
+ | ^^^^^
+ |
+ = help: writing to this reference calls the destructor for the old value
+ = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
+
+error: not automatically applying `DerefMut` on `ManuallyDrop` union field
+ --> $DIR/union-deref.rs:29:14
+ |
+LL | unsafe { u.f.0.0.push(0) };
+ | ^^^^^
+ |
+ = help: writing to this reference calls the destructor for the old value
+ = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
+
+error: aborting due to 6 previous errors
+
--- /dev/null
+error[E0277]: the trait bound `U1: Copy` is not satisfied
+ --> $DIR/union-derive-clone.rs:6:10
+ |
+LL | #[derive(Clone)]
+ | ^^^^^ the trait `Copy` is not implemented for `U1`
+ |
+ ::: $SRC_DIR/core/src/clone.rs:LL:COL
+ |
+LL | pub struct AssertParamIsCopy<T: Copy + ?Sized> {
+ | ---- required by this bound in `AssertParamIsCopy`
+ |
+ = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0599]: the method `clone` exists for union `U5<CloneNoCopy>`, but its trait bounds were not satisfied
+ --> $DIR/union-derive-clone.rs:38:15
+ |
+LL | union U5<T> {
+ | -----------
+ | |
+ | method `clone` not found for this
+ | doesn't satisfy `U5<CloneNoCopy>: Clone`
+...
+LL | struct CloneNoCopy;
+ | ------------------- doesn't satisfy `CloneNoCopy: Copy`
+...
+LL | let w = u.clone();
+ | ^^^^^ method cannot be called on `U5<CloneNoCopy>` due to unsatisfied trait bounds
+ |
+ = note: the following trait bounds were not satisfied:
+ `CloneNoCopy: Copy`
+ which is required by `U5<CloneNoCopy>: Clone`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0277, E0599.
+For more information about an error, try `rustc --explain E0277`.
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
use std::mem::ManuallyDrop;
#[derive(Clone)] //~ ERROR the trait bound `U1: Copy` is not satisfied
+++ /dev/null
-error[E0277]: the trait bound `U1: Copy` is not satisfied
- --> $DIR/union-derive-clone.rs:3:10
- |
-LL | #[derive(Clone)]
- | ^^^^^ the trait `Copy` is not implemented for `U1`
- |
- ::: $SRC_DIR/core/src/clone.rs:LL:COL
- |
-LL | pub struct AssertParamIsCopy<T: Copy + ?Sized> {
- | ---- required by this bound in `AssertParamIsCopy`
- |
- = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0599]: the method `clone` exists for union `U5<CloneNoCopy>`, but its trait bounds were not satisfied
- --> $DIR/union-derive-clone.rs:35:15
- |
-LL | union U5<T> {
- | -----------
- | |
- | method `clone` not found for this
- | doesn't satisfy `U5<CloneNoCopy>: Clone`
-...
-LL | struct CloneNoCopy;
- | ------------------- doesn't satisfy `CloneNoCopy: Copy`
-...
-LL | let w = u.clone();
- | ^^^^^ method cannot be called on `U5<CloneNoCopy>` due to unsatisfied trait bounds
- |
- = note: the following trait bounds were not satisfied:
- `CloneNoCopy: Copy`
- which is required by `U5<CloneNoCopy>: Clone`
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0277, E0599.
-For more information about an error, try `rustc --explain E0277`.
--- /dev/null
+error[E0277]: the trait bound `U1: Copy` is not satisfied
+ --> $DIR/union-derive-clone.rs:6:10
+ |
+LL | #[derive(Clone)]
+ | ^^^^^ the trait `Copy` is not implemented for `U1`
+ |
+ ::: $SRC_DIR/core/src/clone.rs:LL:COL
+ |
+LL | pub struct AssertParamIsCopy<T: Copy + ?Sized> {
+ | ---- required by this bound in `AssertParamIsCopy`
+ |
+ = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0599]: the method `clone` exists for union `U5<CloneNoCopy>`, but its trait bounds were not satisfied
+ --> $DIR/union-derive-clone.rs:38:15
+ |
+LL | union U5<T> {
+ | -----------
+ | |
+ | method `clone` not found for this
+ | doesn't satisfy `U5<CloneNoCopy>: Clone`
+...
+LL | struct CloneNoCopy;
+ | ------------------- doesn't satisfy `CloneNoCopy: Copy`
+...
+LL | let w = u.clone();
+ | ^^^^^ method cannot be called on `U5<CloneNoCopy>` due to unsatisfied trait bounds
+ |
+ = note: the following trait bounds were not satisfied:
+ `CloneNoCopy: Copy`
+ which is required by `U5<CloneNoCopy>: Clone`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0277, E0599.
+For more information about an error, try `rustc --explain E0277`.
--- /dev/null
+error[E0277]: the trait bound `PartialEqNotEq: Eq` is not satisfied
+ --> $DIR/union-derive-eq.rs:16:5
+ |
+LL | a: PartialEqNotEq,
+ | ^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `PartialEqNotEq`
+ |
+ ::: $SRC_DIR/core/src/cmp.rs:LL:COL
+ |
+LL | pub struct AssertParamIsEq<T: Eq + ?Sized> {
+ | -- required by this bound in `AssertParamIsEq`
+ |
+ = note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
#[derive(Eq)] // OK
union U1 {
a: u8,
+++ /dev/null
-error[E0277]: the trait bound `PartialEqNotEq: Eq` is not satisfied
- --> $DIR/union-derive-eq.rs:13:5
- |
-LL | a: PartialEqNotEq,
- | ^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `PartialEqNotEq`
- |
- ::: $SRC_DIR/core/src/cmp.rs:LL:COL
- |
-LL | pub struct AssertParamIsEq<T: Eq + ?Sized> {
- | -- required by this bound in `AssertParamIsEq`
- |
- = note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+error[E0277]: the trait bound `PartialEqNotEq: Eq` is not satisfied
+ --> $DIR/union-derive-eq.rs:16:5
+ |
+LL | a: PartialEqNotEq,
+ | ^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `PartialEqNotEq`
+ |
+ ::: $SRC_DIR/core/src/cmp.rs:LL:COL
+ |
+LL | pub struct AssertParamIsEq<T: Eq + ?Sized> {
+ | -- required by this bound in `AssertParamIsEq`
+ |
+ = note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
#![allow(dead_code)]
#![allow(unused_variables)]
--- /dev/null
+warning: unnecessary `unsafe` block
+ --> $DIR/union-drop.rs:27:9
+ |
+LL | unsafe { CHECK += 1; }
+ | ^^^^^^ unnecessary `unsafe` block
+ |
+ = note: `#[warn(unused_unsafe)]` on by default
+
+warning: unnecessary `unsafe` block
+ --> $DIR/union-drop.rs:33:9
+ |
+LL | unsafe { CHECK += 1; }
+ | ^^^^^^ unnecessary `unsafe` block
+
+warning: unnecessary `unsafe` block
+ --> $DIR/union-drop.rs:40:5
+ |
+LL | unsafe {
+ | ^^^^^^ unnecessary `unsafe` block
+
+warning: 3 warnings emitted
+
--- /dev/null
+error: field is never read: `c`
+ --> $DIR/union-fields-1.rs:9:5
+ |
+LL | c: u8,
+ | ^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/union-fields-1.rs:4:9
+ |
+LL | #![deny(dead_code)]
+ | ^^^^^^^^^
+
+error: field is never read: `a`
+ --> $DIR/union-fields-1.rs:12:5
+ |
+LL | a: u8,
+ | ^^^^^
+
+error: field is never read: `a`
+ --> $DIR/union-fields-1.rs:16:20
+ |
+LL | union NoDropLike { a: u8 }
+ | ^^^^^
+
+error: field is never read: `c`
+ --> $DIR/union-fields-1.rs:21:5
+ |
+LL | c: u8,
+ | ^^^^^
+
+error: aborting due to 4 previous errors
+
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
#![deny(dead_code)]
union U1 {
+++ /dev/null
-error: field is never read: `c`
- --> $DIR/union-fields-1.rs:6:5
- |
-LL | c: u8,
- | ^^^^^
- |
-note: the lint level is defined here
- --> $DIR/union-fields-1.rs:1:9
- |
-LL | #![deny(dead_code)]
- | ^^^^^^^^^
-
-error: field is never read: `a`
- --> $DIR/union-fields-1.rs:9:5
- |
-LL | a: u8,
- | ^^^^^
-
-error: field is never read: `a`
- --> $DIR/union-fields-1.rs:13:20
- |
-LL | union NoDropLike { a: u8 }
- | ^^^^^
-
-error: field is never read: `c`
- --> $DIR/union-fields-1.rs:18:5
- |
-LL | c: u8,
- | ^^^^^
-
-error: aborting due to 4 previous errors
-
--- /dev/null
+error: field is never read: `c`
+ --> $DIR/union-fields-1.rs:9:5
+ |
+LL | c: u8,
+ | ^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/union-fields-1.rs:4:9
+ |
+LL | #![deny(dead_code)]
+ | ^^^^^^^^^
+
+error: field is never read: `a`
+ --> $DIR/union-fields-1.rs:12:5
+ |
+LL | a: u8,
+ | ^^^^^
+
+error: field is never read: `a`
+ --> $DIR/union-fields-1.rs:16:20
+ |
+LL | union NoDropLike { a: u8 }
+ | ^^^^^
+
+error: field is never read: `c`
+ --> $DIR/union-fields-1.rs:21:5
+ |
+LL | c: u8,
+ | ^^^^^
+
+error: aborting due to 4 previous errors
+
--- /dev/null
+error: union expressions should have exactly one field
+ --> $DIR/union-fields-2.rs:10:13
+ |
+LL | let u = U {};
+ | ^
+
+error: union expressions should have exactly one field
+ --> $DIR/union-fields-2.rs:12:13
+ |
+LL | let u = U { a: 0, b: 1 };
+ | ^
+
+error[E0560]: union `U` has no field named `c`
+ --> $DIR/union-fields-2.rs:13:29
+ |
+LL | let u = U { a: 0, b: 1, c: 2 };
+ | ^ `U` does not have this field
+ |
+ = note: available fields are: `a`, `b`
+
+error: union expressions should have exactly one field
+ --> $DIR/union-fields-2.rs:13:13
+ |
+LL | let u = U { a: 0, b: 1, c: 2 };
+ | ^
+
+error: union expressions should have exactly one field
+ --> $DIR/union-fields-2.rs:15:13
+ |
+LL | let u = U { ..u };
+ | ^
+
+error[E0436]: functional record update syntax requires a struct
+ --> $DIR/union-fields-2.rs:15:19
+ |
+LL | let u = U { ..u };
+ | ^
+
+error: union patterns should have exactly one field
+ --> $DIR/union-fields-2.rs:18:9
+ |
+LL | let U {} = u;
+ | ^^^^
+
+error: union patterns should have exactly one field
+ --> $DIR/union-fields-2.rs:20:9
+ |
+LL | let U { a, b } = u;
+ | ^^^^^^^^^^
+
+error: union patterns should have exactly one field
+ --> $DIR/union-fields-2.rs:21:9
+ |
+LL | let U { a, b, c } = u;
+ | ^^^^^^^^^^^^^
+
+error[E0026]: union `U` does not have a field named `c`
+ --> $DIR/union-fields-2.rs:21:19
+ |
+LL | let U { a, b, c } = u;
+ | ^ union `U` does not have this field
+
+error: union patterns should have exactly one field
+ --> $DIR/union-fields-2.rs:23:9
+ |
+LL | let U { .. } = u;
+ | ^^^^^^^^
+
+error: `..` cannot be used in union patterns
+ --> $DIR/union-fields-2.rs:23:9
+ |
+LL | let U { .. } = u;
+ | ^^^^^^^^
+
+error: `..` cannot be used in union patterns
+ --> $DIR/union-fields-2.rs:25:9
+ |
+LL | let U { a, .. } = u;
+ | ^^^^^^^^^^^
+
+error: aborting due to 13 previous errors
+
+Some errors have detailed explanations: E0026, E0436, E0560.
+For more information about an error, try `rustc --explain E0026`.
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
union U {
a: u8,
b: u16,
+++ /dev/null
-error: union expressions should have exactly one field
- --> $DIR/union-fields-2.rs:7:13
- |
-LL | let u = U {};
- | ^
-
-error: union expressions should have exactly one field
- --> $DIR/union-fields-2.rs:9:13
- |
-LL | let u = U { a: 0, b: 1 };
- | ^
-
-error[E0560]: union `U` has no field named `c`
- --> $DIR/union-fields-2.rs:10:29
- |
-LL | let u = U { a: 0, b: 1, c: 2 };
- | ^ `U` does not have this field
- |
- = note: available fields are: `a`, `b`
-
-error: union expressions should have exactly one field
- --> $DIR/union-fields-2.rs:10:13
- |
-LL | let u = U { a: 0, b: 1, c: 2 };
- | ^
-
-error: union expressions should have exactly one field
- --> $DIR/union-fields-2.rs:12:13
- |
-LL | let u = U { ..u };
- | ^
-
-error[E0436]: functional record update syntax requires a struct
- --> $DIR/union-fields-2.rs:12:19
- |
-LL | let u = U { ..u };
- | ^
-
-error: union patterns should have exactly one field
- --> $DIR/union-fields-2.rs:15:9
- |
-LL | let U {} = u;
- | ^^^^
-
-error: union patterns should have exactly one field
- --> $DIR/union-fields-2.rs:17:9
- |
-LL | let U { a, b } = u;
- | ^^^^^^^^^^
-
-error: union patterns should have exactly one field
- --> $DIR/union-fields-2.rs:18:9
- |
-LL | let U { a, b, c } = u;
- | ^^^^^^^^^^^^^
-
-error[E0026]: union `U` does not have a field named `c`
- --> $DIR/union-fields-2.rs:18:19
- |
-LL | let U { a, b, c } = u;
- | ^ union `U` does not have this field
-
-error: union patterns should have exactly one field
- --> $DIR/union-fields-2.rs:20:9
- |
-LL | let U { .. } = u;
- | ^^^^^^^^
-
-error: `..` cannot be used in union patterns
- --> $DIR/union-fields-2.rs:20:9
- |
-LL | let U { .. } = u;
- | ^^^^^^^^
-
-error: `..` cannot be used in union patterns
- --> $DIR/union-fields-2.rs:22:9
- |
-LL | let U { a, .. } = u;
- | ^^^^^^^^^^^
-
-error: aborting due to 13 previous errors
-
-Some errors have detailed explanations: E0026, E0436, E0560.
-For more information about an error, try `rustc --explain E0026`.
--- /dev/null
+error: union expressions should have exactly one field
+ --> $DIR/union-fields-2.rs:10:13
+ |
+LL | let u = U {};
+ | ^
+
+error: union expressions should have exactly one field
+ --> $DIR/union-fields-2.rs:12:13
+ |
+LL | let u = U { a: 0, b: 1 };
+ | ^
+
+error[E0560]: union `U` has no field named `c`
+ --> $DIR/union-fields-2.rs:13:29
+ |
+LL | let u = U { a: 0, b: 1, c: 2 };
+ | ^ `U` does not have this field
+ |
+ = note: available fields are: `a`, `b`
+
+error: union expressions should have exactly one field
+ --> $DIR/union-fields-2.rs:13:13
+ |
+LL | let u = U { a: 0, b: 1, c: 2 };
+ | ^
+
+error: union expressions should have exactly one field
+ --> $DIR/union-fields-2.rs:15:13
+ |
+LL | let u = U { ..u };
+ | ^
+
+error[E0436]: functional record update syntax requires a struct
+ --> $DIR/union-fields-2.rs:15:19
+ |
+LL | let u = U { ..u };
+ | ^
+
+error: union patterns should have exactly one field
+ --> $DIR/union-fields-2.rs:18:9
+ |
+LL | let U {} = u;
+ | ^^^^
+
+error: union patterns should have exactly one field
+ --> $DIR/union-fields-2.rs:20:9
+ |
+LL | let U { a, b } = u;
+ | ^^^^^^^^^^
+
+error: union patterns should have exactly one field
+ --> $DIR/union-fields-2.rs:21:9
+ |
+LL | let U { a, b, c } = u;
+ | ^^^^^^^^^^^^^
+
+error[E0026]: union `U` does not have a field named `c`
+ --> $DIR/union-fields-2.rs:21:19
+ |
+LL | let U { a, b, c } = u;
+ | ^ union `U` does not have this field
+
+error: union patterns should have exactly one field
+ --> $DIR/union-fields-2.rs:23:9
+ |
+LL | let U { .. } = u;
+ | ^^^^^^^^
+
+error: `..` cannot be used in union patterns
+ --> $DIR/union-fields-2.rs:23:9
+ |
+LL | let U { .. } = u;
+ | ^^^^^^^^
+
+error: `..` cannot be used in union patterns
+ --> $DIR/union-fields-2.rs:25:9
+ |
+LL | let U { a, .. } = u;
+ | ^^^^^^^^^^^
+
+error: aborting due to 13 previous errors
+
+Some errors have detailed explanations: E0026, E0436, E0560.
+For more information about an error, try `rustc --explain E0026`.
// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
#![allow(dead_code)]
use std::mem::ManuallyDrop;
--- /dev/null
+error[E0277]: the trait bound `Rc<u32>: Copy` is not satisfied
+ --> $DIR/union-generic.rs:11:13
+ |
+LL | union U<T: Copy> {
+ | ---------------- required by `U`
+...
+LL | let u = U { a: Rc::new(0u32) };
+ | ^ the trait `Copy` is not implemented for `Rc<u32>`
+
+error[E0277]: the trait bound `Rc<u32>: Copy` is not satisfied
+ --> $DIR/union-generic.rs:13:13
+ |
+LL | union U<T: Copy> {
+ | ---------------- required by `U`
+...
+LL | let u = U::<Rc<u32>> { a: Default::default() };
+ | ^^^^^^^^^^^^ the trait `Copy` is not implemented for `Rc<u32>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
use std::rc::Rc;
union U<T: Copy> {
+++ /dev/null
-error[E0277]: the trait bound `Rc<u32>: Copy` is not satisfied
- --> $DIR/union-generic.rs:8:13
- |
-LL | union U<T: Copy> {
- | ---------------- required by `U`
-...
-LL | let u = U { a: Rc::new(0u32) };
- | ^ the trait `Copy` is not implemented for `Rc<u32>`
-
-error[E0277]: the trait bound `Rc<u32>: Copy` is not satisfied
- --> $DIR/union-generic.rs:10:13
- |
-LL | union U<T: Copy> {
- | ---------------- required by `U`
-...
-LL | let u = U::<Rc<u32>> { a: Default::default() };
- | ^^^^^^^^^^^^ the trait `Copy` is not implemented for `Rc<u32>`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+error[E0277]: the trait bound `Rc<u32>: Copy` is not satisfied
+ --> $DIR/union-generic.rs:11:13
+ |
+LL | union U<T: Copy> {
+ | ---------------- required by `U`
+...
+LL | let u = U { a: Rc::new(0u32) };
+ | ^ the trait `Copy` is not implemented for `Rc<u32>`
+
+error[E0277]: the trait bound `Rc<u32>: Copy` is not satisfied
+ --> $DIR/union-generic.rs:13:13
+ |
+LL | union U<T: Copy> {
+ | ---------------- required by `U`
+...
+LL | let u = U::<Rc<u32>> { a: Default::default() };
+ | ^^^^^^^^^^^^ the trait `Copy` is not implemented for `Rc<u32>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
union U {
a: u8,
--- /dev/null
+error: field is never read: `b`
+ --> $DIR/union-lint-dead-code.rs:8:5
+ |
+LL | b: bool,
+ | ^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/union-lint-dead-code.rs:4:9
+ |
+LL | #![deny(dead_code)]
+ | ^^^^^^^^^
+
+error: aborting due to previous error
+
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
#![deny(dead_code)]
union Foo {
+++ /dev/null
-error: field is never read: `b`
- --> $DIR/union-lint-dead-code.rs:5:5
- |
-LL | b: bool,
- | ^^^^^^^
- |
-note: the lint level is defined here
- --> $DIR/union-lint-dead-code.rs:1:9
- |
-LL | #![deny(dead_code)]
- | ^^^^^^^^^
-
-error: aborting due to previous error
-
--- /dev/null
+error: field is never read: `b`
+ --> $DIR/union-lint-dead-code.rs:8:5
+ |
+LL | b: bool,
+ | ^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/union-lint-dead-code.rs:4:9
+ |
+LL | #![deny(dead_code)]
+ | ^^^^^^^^^
+
+error: aborting due to previous error
+
// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
#![allow(unused_variables)]
macro_rules! duplicate {
-#![allow(dead_code)]
// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
+#![allow(dead_code)]
use std::mem::needs_drop;
use std::mem::ManuallyDrop;
--- /dev/null
+error[E0382]: use of moved value: `x`
+ --> $DIR/union-move.rs:29:18
+ |
+LL | fn test1(x: U1) {
+ | - move occurs because `x` has type `U1`, which does not implement the `Copy` trait
+...
+LL | move_out(x.f1_nocopy);
+ | ----------- value moved here
+LL | move_out(x.f2_nocopy);
+ | ^^^^^^^^^^^ value used here after move
+
+error[E0382]: use of moved value: `x`
+ --> $DIR/union-move.rs:45:18
+ |
+LL | fn test3(x: U1) {
+ | - move occurs because `x` has type `U1`, which does not implement the `Copy` trait
+...
+LL | move_out(x.f2_nocopy);
+ | ----------- value moved here
+LL | move_out(x.f3_copy);
+ | ^^^^^^^^^ value used here after move
+
+error[E0509]: cannot move out of type `U2`, which implements the `Drop` trait
+ --> $DIR/union-move.rs:52:18
+ |
+LL | move_out(x.f1_nocopy);
+ | ^^^^^^^^^^^
+ | |
+ | cannot move out of here
+ | move occurs because `x.f1_nocopy` has type `RefCell<i32>`, which does not implement the `Copy` trait
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0382, E0509.
+For more information about an error, try `rustc --explain E0382`.
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
//! Test the behavior of moving out of non-`Copy` union fields.
//! Avoid types that `Drop`, we want to focus on moving.
#![feature(untagged_unions)]
+++ /dev/null
-error[E0382]: use of moved value: `x`
- --> $DIR/union-move.rs:26:18
- |
-LL | fn test1(x: U1) {
- | - move occurs because `x` has type `U1`, which does not implement the `Copy` trait
-...
-LL | move_out(x.f1_nocopy);
- | ----------- value moved here
-LL | move_out(x.f2_nocopy);
- | ^^^^^^^^^^^ value used here after move
-
-error[E0382]: use of moved value: `x`
- --> $DIR/union-move.rs:42:18
- |
-LL | fn test3(x: U1) {
- | - move occurs because `x` has type `U1`, which does not implement the `Copy` trait
-...
-LL | move_out(x.f2_nocopy);
- | ----------- value moved here
-LL | move_out(x.f3_copy);
- | ^^^^^^^^^ value used here after move
-
-error[E0509]: cannot move out of type `U2`, which implements the `Drop` trait
- --> $DIR/union-move.rs:49:18
- |
-LL | move_out(x.f1_nocopy);
- | ^^^^^^^^^^^
- | |
- | cannot move out of here
- | move occurs because `x.f1_nocopy` has type `RefCell<i32>`, which does not implement the `Copy` trait
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0382, E0509.
-For more information about an error, try `rustc --explain E0382`.
--- /dev/null
+error[E0382]: use of moved value: `x`
+ --> $DIR/union-move.rs:29:18
+ |
+LL | fn test1(x: U1) {
+ | - move occurs because `x` has type `U1`, which does not implement the `Copy` trait
+...
+LL | move_out(x.f1_nocopy);
+ | ----------- value moved here
+LL | move_out(x.f2_nocopy);
+ | ^^^^^^^^^^^ value used here after move
+
+error[E0382]: use of moved value: `x`
+ --> $DIR/union-move.rs:45:18
+ |
+LL | fn test3(x: U1) {
+ | - move occurs because `x` has type `U1`, which does not implement the `Copy` trait
+...
+LL | move_out(x.f2_nocopy);
+ | ----------- value moved here
+LL | move_out(x.f3_copy);
+ | ^^^^^^^^^ value used here after move
+
+error[E0509]: cannot move out of type `U2`, which implements the `Drop` trait
+ --> $DIR/union-move.rs:52:18
+ |
+LL | move_out(x.f1_nocopy);
+ | ^^^^^^^^^^^
+ | |
+ | cannot move out of here
+ | move occurs because `x.f1_nocopy` has type `RefCell<i32>`, which does not implement the `Copy` trait
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0382, E0509.
+For more information about an error, try `rustc --explain E0382`.
// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
#![allow(dead_code)]
// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
#![allow(dead_code)]
// Tests that unions aren't subject to unsafe non-zero/niche-filling optimizations.
// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
#[repr(C)]
#[derive(Copy, Clone)]
// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
#![allow(dead_code)]
#![allow(non_snake_case)]
// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
#![allow(dead_code)]
#![allow(illegal_floating_point_literal_pattern)]
--- /dev/null
+error[E0560]: union `U` has no field named `principle`
+ --> $DIR/union-suggest-field.rs:13:17
+ |
+LL | let u = U { principle: 0 };
+ | ^^^^^^^^^ help: a field with a similar name exists: `principal`
+
+error[E0609]: no field `principial` on type `U`
+ --> $DIR/union-suggest-field.rs:17:15
+ |
+LL | let w = u.principial;
+ | ^^^^^^^^^^ help: a field with a similar name exists: `principal`
+
+error[E0615]: attempted to take value of method `calculate` on type `U`
+ --> $DIR/union-suggest-field.rs:21:15
+ |
+LL | let y = u.calculate;
+ | ^^^^^^^^^ method, not a field
+ |
+help: use parentheses to call the method
+ |
+LL | let y = u.calculate();
+ | ^^
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0560, E0609, E0615.
+For more information about an error, try `rustc --explain E0560`.
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
union U {
principal: u8,
}
+++ /dev/null
-error[E0560]: union `U` has no field named `principle`
- --> $DIR/union-suggest-field.rs:10:17
- |
-LL | let u = U { principle: 0 };
- | ^^^^^^^^^ help: a field with a similar name exists: `principal`
-
-error[E0609]: no field `principial` on type `U`
- --> $DIR/union-suggest-field.rs:14:15
- |
-LL | let w = u.principial;
- | ^^^^^^^^^^ help: a field with a similar name exists: `principal`
-
-error[E0615]: attempted to take value of method `calculate` on type `U`
- --> $DIR/union-suggest-field.rs:18:15
- |
-LL | let y = u.calculate;
- | ^^^^^^^^^ method, not a field
- |
-help: use parentheses to call the method
- |
-LL | let y = u.calculate();
- | ^^
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0560, E0609, E0615.
-For more information about an error, try `rustc --explain E0560`.
--- /dev/null
+error[E0560]: union `U` has no field named `principle`
+ --> $DIR/union-suggest-field.rs:13:17
+ |
+LL | let u = U { principle: 0 };
+ | ^^^^^^^^^ help: a field with a similar name exists: `principal`
+
+error[E0609]: no field `principial` on type `U`
+ --> $DIR/union-suggest-field.rs:17:15
+ |
+LL | let w = u.principial;
+ | ^^^^^^^^^^ help: a field with a similar name exists: `principal`
+
+error[E0615]: attempted to take value of method `calculate` on type `U`
+ --> $DIR/union-suggest-field.rs:21:15
+ |
+LL | let y = u.calculate;
+ | ^^^^^^^^^ method, not a field
+ |
+help: use parentheses to call the method
+ |
+LL | let y = u.calculate();
+ | ^^
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0560, E0609, E0615.
+For more information about an error, try `rustc --explain E0560`.
// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
use std::fmt;
// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
union U {
a: (u8, u8),
--- /dev/null
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:34:5
+ |
+LL | *(u.p) = 13;
+ | ^^^^^^^^^^^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:39:5
+ |
+LL | u.a = (RefCell::new(0), 1);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to union field that might need dropping
+ |
+ = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized
+
+error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:40:5
+ |
+LL | u.a.0 = RefCell::new(0);
+ | ^^^^^^^^^^^^^^^^^^^^^^^ assignment to union field that might need dropping
+ |
+ = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:47:6
+ |
+LL | *u3.a = T::default();
+ | ^^^^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:53:6
+ |
+LL | *u3.a = T::default();
+ | ^^^^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:61:13
+ |
+LL | let a = u1.a;
+ | ^^^^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:64:14
+ |
+LL | let U1 { a } = u1;
+ | ^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:65:20
+ |
+LL | if let U1 { a: 12 } = u1 {}
+ | ^^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:70:6
+ |
+LL | *u2.a = String::from("new");
+ | ^^^^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:74:6
+ |
+LL | *u3.a = 1;
+ | ^^^^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:78:6
+ |
+LL | *u3.a = String::from("new");
+ | ^^^^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error: aborting due to 11 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
#![feature(untagged_unions)]
use std::mem::ManuallyDrop;
use std::cell::RefCell;
}
fn assign_noncopy_union_field(mut u: URefCell) {
- u.a = (RefCell::new(0), 1); //~ ERROR assignment to union field that might need dropping
- u.a.0 = RefCell::new(0); //~ ERROR assignment to union field that might need dropping
+ // FIXME(thir-unsafeck)
+ u.a = (RefCell::new(0), 1); //[mir]~ ERROR assignment to union field that might need dropping
+ u.a.0 = RefCell::new(0); //[mir]~ ERROR assignment to union field that might need dropping
u.a.1 = 1; // OK
}
+++ /dev/null
-error[E0133]: access to union field is unsafe and requires unsafe function or block
- --> $DIR/union-unsafe.rs:31:5
- |
-LL | *(u.p) = 13;
- | ^^^^^^^^^^^ access to union field
- |
- = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
-
-error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block
- --> $DIR/union-unsafe.rs:35:5
- |
-LL | u.a = (RefCell::new(0), 1);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to union field that might need dropping
- |
- = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized
-
-error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block
- --> $DIR/union-unsafe.rs:36:5
- |
-LL | u.a.0 = RefCell::new(0);
- | ^^^^^^^^^^^^^^^^^^^^^^^ assignment to union field that might need dropping
- |
- = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized
-
-error[E0133]: access to union field is unsafe and requires unsafe function or block
- --> $DIR/union-unsafe.rs:43:6
- |
-LL | *u3.a = T::default();
- | ^^^^ access to union field
- |
- = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
-
-error[E0133]: access to union field is unsafe and requires unsafe function or block
- --> $DIR/union-unsafe.rs:49:6
- |
-LL | *u3.a = T::default();
- | ^^^^ access to union field
- |
- = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
-
-error[E0133]: access to union field is unsafe and requires unsafe function or block
- --> $DIR/union-unsafe.rs:57:13
- |
-LL | let a = u1.a;
- | ^^^^ access to union field
- |
- = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
-
-error[E0133]: access to union field is unsafe and requires unsafe function or block
- --> $DIR/union-unsafe.rs:60:14
- |
-LL | let U1 { a } = u1;
- | ^ access to union field
- |
- = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
-
-error[E0133]: access to union field is unsafe and requires unsafe function or block
- --> $DIR/union-unsafe.rs:61:20
- |
-LL | if let U1 { a: 12 } = u1 {}
- | ^^ access to union field
- |
- = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
-
-error[E0133]: access to union field is unsafe and requires unsafe function or block
- --> $DIR/union-unsafe.rs:66:6
- |
-LL | *u2.a = String::from("new");
- | ^^^^ access to union field
- |
- = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
-
-error[E0133]: access to union field is unsafe and requires unsafe function or block
- --> $DIR/union-unsafe.rs:70:6
- |
-LL | *u3.a = 1;
- | ^^^^ access to union field
- |
- = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
-
-error[E0133]: access to union field is unsafe and requires unsafe function or block
- --> $DIR/union-unsafe.rs:74:6
- |
-LL | *u3.a = String::from("new");
- | ^^^^ access to union field
- |
- = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
-
-error: aborting due to 11 previous errors
-
-For more information about this error, try `rustc --explain E0133`.
--- /dev/null
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:34:6
+ |
+LL | *(u.p) = 13;
+ | ^^^^^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:47:6
+ |
+LL | *u3.a = T::default();
+ | ^^^^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:53:6
+ |
+LL | *u3.a = T::default();
+ | ^^^^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:61:13
+ |
+LL | let a = u1.a;
+ | ^^^^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:64:14
+ |
+LL | let U1 { a } = u1;
+ | ^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:65:20
+ |
+LL | if let U1 { a: 12 } = u1 {}
+ | ^^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:70:6
+ |
+LL | *u2.a = String::from("new");
+ | ^^^^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:74:6
+ |
+LL | *u3.a = 1;
+ | ^^^^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:78:6
+ |
+LL | *u3.a = String::from("new");
+ | ^^^^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error: aborting due to 9 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
--- /dev/null
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+ --> $DIR/union-unsized.rs:7:8
+ |
+LL | a: str,
+ | ^^^ doesn't have a size known at compile-time
+ |
+ = help: the trait `Sized` is not implemented for `str`
+ = note: no field of a union may have a dynamically sized type
+ = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+ |
+LL | a: &str,
+ | ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+ |
+LL | a: Box<str>,
+ | ^^^^ ^
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+ --> $DIR/union-unsized.rs:15:8
+ |
+LL | b: str,
+ | ^^^ doesn't have a size known at compile-time
+ |
+ = help: the trait `Sized` is not implemented for `str`
+ = note: no field of a union may have a dynamically sized type
+ = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+ |
+LL | b: &str,
+ | ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+ |
+LL | b: Box<str>,
+ | ^^^^ ^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
#![feature(untagged_unions)]
union U {
+++ /dev/null
-error[E0277]: the size for values of type `str` cannot be known at compilation time
- --> $DIR/union-unsized.rs:4:8
- |
-LL | a: str,
- | ^^^ doesn't have a size known at compile-time
- |
- = help: the trait `Sized` is not implemented for `str`
- = note: no field of a union may have a dynamically sized type
- = help: change the field's type to have a statically known size
-help: borrowed types always have a statically known size
- |
-LL | a: &str,
- | ^
-help: the `Box` type always has a statically known size and allocates its contents in the heap
- |
-LL | a: Box<str>,
- | ^^^^ ^
-
-error[E0277]: the size for values of type `str` cannot be known at compilation time
- --> $DIR/union-unsized.rs:12:8
- |
-LL | b: str,
- | ^^^ doesn't have a size known at compile-time
- |
- = help: the trait `Sized` is not implemented for `str`
- = note: no field of a union may have a dynamically sized type
- = help: change the field's type to have a statically known size
-help: borrowed types always have a statically known size
- |
-LL | b: &str,
- | ^
-help: the `Box` type always has a statically known size and allocates its contents in the heap
- |
-LL | b: Box<str>,
- | ^^^^ ^
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+ --> $DIR/union-unsized.rs:7:8
+ |
+LL | a: str,
+ | ^^^ doesn't have a size known at compile-time
+ |
+ = help: the trait `Sized` is not implemented for `str`
+ = note: no field of a union may have a dynamically sized type
+ = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+ |
+LL | a: &str,
+ | ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+ |
+LL | a: Box<str>,
+ | ^^^^ ^
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+ --> $DIR/union-unsized.rs:15:8
+ |
+LL | b: str,
+ | ^^^ doesn't have a size known at compile-time
+ |
+ = help: the trait `Sized` is not implemented for `str`
+ = note: no field of a union may have a dynamically sized type
+ = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+ |
+LL | b: &str,
+ | ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+ |
+LL | b: Box<str>,
+ | ^^^^ ^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+error[E0740]: unions may not contain fields that need dropping
+ --> $DIR/union-with-drop-fields.rs:11:5
+ |
+LL | a: String,
+ | ^^^^^^^^^
+ |
+note: `std::mem::ManuallyDrop` can be used to wrap the type
+ --> $DIR/union-with-drop-fields.rs:11:5
+ |
+LL | a: String,
+ | ^^^^^^^^^
+
+error[E0740]: unions may not contain fields that need dropping
+ --> $DIR/union-with-drop-fields.rs:19:5
+ |
+LL | a: S,
+ | ^^^^
+ |
+note: `std::mem::ManuallyDrop` can be used to wrap the type
+ --> $DIR/union-with-drop-fields.rs:19:5
+ |
+LL | a: S,
+ | ^^^^
+
+error[E0740]: unions may not contain fields that need dropping
+ --> $DIR/union-with-drop-fields.rs:24:5
+ |
+LL | a: T,
+ | ^^^^
+ |
+note: `std::mem::ManuallyDrop` can be used to wrap the type
+ --> $DIR/union-with-drop-fields.rs:24:5
+ |
+LL | a: T,
+ | ^^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0740`.
-#![feature(untagged_unions)]
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
#![allow(dead_code)]
union U {
+++ /dev/null
-error[E0740]: unions may not contain fields that need dropping
- --> $DIR/union-with-drop-fields.rs:9:5
- |
-LL | a: String,
- | ^^^^^^^^^
- |
-note: `std::mem::ManuallyDrop` can be used to wrap the type
- --> $DIR/union-with-drop-fields.rs:9:5
- |
-LL | a: String,
- | ^^^^^^^^^
-
-error[E0740]: unions may not contain fields that need dropping
- --> $DIR/union-with-drop-fields.rs:17:5
- |
-LL | a: S,
- | ^^^^
- |
-note: `std::mem::ManuallyDrop` can be used to wrap the type
- --> $DIR/union-with-drop-fields.rs:17:5
- |
-LL | a: S,
- | ^^^^
-
-error[E0740]: unions may not contain fields that need dropping
- --> $DIR/union-with-drop-fields.rs:22:5
- |
-LL | a: T,
- | ^^^^
- |
-note: `std::mem::ManuallyDrop` can be used to wrap the type
- --> $DIR/union-with-drop-fields.rs:22:5
- |
-LL | a: T,
- | ^^^^
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0740`.
--- /dev/null
+error[E0740]: unions may not contain fields that need dropping
+ --> $DIR/union-with-drop-fields.rs:11:5
+ |
+LL | a: String,
+ | ^^^^^^^^^
+ |
+note: `std::mem::ManuallyDrop` can be used to wrap the type
+ --> $DIR/union-with-drop-fields.rs:11:5
+ |
+LL | a: String,
+ | ^^^^^^^^^
+
+error[E0740]: unions may not contain fields that need dropping
+ --> $DIR/union-with-drop-fields.rs:19:5
+ |
+LL | a: S,
+ | ^^^^
+ |
+note: `std::mem::ManuallyDrop` can be used to wrap the type
+ --> $DIR/union-with-drop-fields.rs:19:5
+ |
+LL | a: S,
+ | ^^^^
+
+error[E0740]: unions may not contain fields that need dropping
+ --> $DIR/union-with-drop-fields.rs:24:5
+ |
+LL | a: T,
+ | ^^^^
+ |
+note: `std::mem::ManuallyDrop` can be used to wrap the type
+ --> $DIR/union-with-drop-fields.rs:24:5
+ |
+LL | a: T,
+ | ^^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0740`.
--- /dev/null
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/access_union_field.rs:13:13
+ |
+LL | let a = foo.bar;
+ | ^^^^^^^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/access_union_field.rs:14:13
+ |
+LL | let b = foo.baz;
+ | ^^^^^^^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
--- /dev/null
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
+#![allow(unused_variables)]
+
+union Foo {
+ bar: i8,
+ baz: u8,
+}
+
+fn main() {
+ let foo = Foo { bar: 5 };
+ let a = foo.bar; //~ ERROR access to union field is unsafe and requires unsafe function or block
+ let b = foo.baz; //~ ERROR access to union field is unsafe and requires unsafe function or block
+}
--- /dev/null
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/access_union_field.rs:13:13
+ |
+LL | let a = foo.bar;
+ | ^^^^^^^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/access_union_field.rs:14:13
+ |
+LL | let b = foo.baz;
+ | ^^^^^^^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
--- /dev/null
+warning: unnecessary `unsafe` block
+ --> $DIR/union.rs:61:5
+ |
+LL | unsafe {
+ | ^^^^^^ unnecessary `unsafe` block
+ |
+ = note: `#[warn(unused_unsafe)]` on by default
+
+warning: unnecessary `unsafe` block
+ --> $DIR/union.rs:66:5
+ |
+LL | unsafe {
+ | ^^^^^^ unnecessary `unsafe` block
+
+warning: 2 warnings emitted
+
--- /dev/null
+// run-pass
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
+#![feature(untagged_unions)]
+
+union Foo {
+ bar: i8,
+ zst: (),
+ pizza: Pizza,
+}
+
+struct Pizza {
+ topping: Option<PizzaTopping>
+}
+
+#[allow(dead_code)]
+enum PizzaTopping {
+ Cheese,
+ Pineapple,
+}
+
+struct FooHolder {
+ inner_foo: Foo
+}
+
+fn do_nothing(_x: &mut Foo) {}
+
+pub fn main() {
+ let mut foo = Foo { bar: 5 };
+ do_nothing(&mut foo);
+ foo.bar = 6;
+ unsafe { foo.bar += 1; }
+ assert_eq!(unsafe { foo.bar }, 7);
+ unsafe {
+ let Foo { bar: inner } = foo;
+ assert_eq!(inner, 7);
+ }
+ let foo = if let true = true { foo } else { foo };
+
+ unsafe {
+ match foo {
+ Foo { bar: _a } => {},
+ }
+ }
+ unsafe {
+ match foo {
+ Foo {
+ pizza: Pizza {
+ topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping::Pineapple) | None
+ }
+ } => {},
+ }
+ }
+ // binding to wildcard is okay
+ match foo {
+ Foo { bar: _ } => {},
+ }
+ let Foo { bar: _ } = foo;
+ // MIR unsafeck incorrectly thinks that it is safe to do these
+ unsafe { //[mir]~ WARNING
+ match foo {
+ Foo { zst: () } => {},
+ }
+ }
+ unsafe { //[mir]~ WARNING
+ match foo {
+ Foo { pizza: Pizza { .. } } => {},
+ }
+ }
+ let foo = Foo { bar: 5 };
+ let foo = if let 3 = if let true = true { 3 } else { 4 } { foo } else { foo };
+
+ let (_foo2, _random) = (foo, 42);
+
+ let mut foo_holder = FooHolder { inner_foo: Foo { bar: 5 } };
+ foo_holder.inner_foo.bar = 4;
+ assert_eq!(unsafe { foo_holder.inner_foo.bar }, 4);
+ drop(foo_holder);
+}
--- /dev/null
+// check-pass
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
+#[derive(Copy, Clone)]
+pub struct Foo { a: bool }
+
+pub union Bar {
+ a: Foo,
+ b: u32,
+}
+pub fn baz(mut bar: Bar) {
+ unsafe {
+ { bar.a }.a = true;
+ }
+}
+
+fn main() {}
--- /dev/null
+warning: unnecessary `unsafe` block
+ --> $DIR/union_destructure.rs:35:5
+ |
+LL | unsafe {
+ | ^^^^^^ unnecessary `unsafe` block
+ |
+ = note: `#[warn(unused_unsafe)]` on by default
+
+warning: unnecessary `unsafe` block
+ --> $DIR/union_destructure.rs:41:5
+ |
+LL | unsafe {
+ | ^^^^^^ unnecessary `unsafe` block
+
+warning: 2 warnings emitted
+
--- /dev/null
+// run-pass
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
+#[derive(Copy, Clone)]
+#[allow(dead_code)]
+struct Pie {
+ slices: u8,
+ size: u8,
+}
+
+union Foo {
+ #[allow(dead_code)]
+ bar: i8,
+ baz: Pie
+}
+
+fn main() {
+ let u = Foo { bar: 5 };
+ let (Some(Foo { bar: _ }) | None) = Some(u);
+ let u = Foo { bar: 6 };
+ let (Some(Foo { bar: _ }) | Some(Foo { bar: _ }) | None) = Some(u);
+ unsafe {
+ let u = Foo { bar: 7 };
+ let (Foo { bar } | Foo { bar }) = u;
+ assert_eq!(bar, 7)
+ }
+ let u = Foo { bar: 8 };
+ match Some(u) {
+ Some(Foo { bar: _ }) => 3,
+ None => 4,
+ };
+
+ let u = Foo { bar: 9 };
+ unsafe { //[mir]~ WARNING unnecessary `unsafe` block
+ match u {
+ Foo { baz: Pie { .. } } => {},
+ };
+ }
+ let u = Foo { bar: 10 };
+ unsafe { //[mir]~ WARNING unnecessary `unsafe` block
+ match u {
+ Foo { baz: Pie { slices: _, size: _ } } => {},
+ };
+ }
+
+ let u = Foo { bar: 11 };
+ match u {
+ Foo { baz: _ } => {},
+ };
+}
--- /dev/null
+// check-pass
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
+union X { a: i8 }
+
+fn main() {
+ let x = X { a: 5 };
+ match x {
+ X { a: _ | _ } => {},
+ }
+}