Auto merge of #138866 - compiler-errors:rollup-9d8v3mz, r=compiler-errors

Rollup of 12 pull requests

Successful merges:

 - #136040 (Remove unused trait BoundedSize)
 - #138236 (uefi: Add OwnedEvent abstraction)
 - #138293 (rustdoc: Gate unstable `doc(cfg())` predicates)
 - #138509 (Add test to ensure no index out of bounds panic (#135474))
 - #138545 (Add MIR pre-codegen tests to track #138544)
 - #138631 (Update test for SGX now implementing `read_buf`)
 - #138641 (Add unstable `--print=supported-crate-types` option)
 - #138667 (std: uefi: fs: Implement mkdir)
 - #138849 (doc: rename reference #create-a-configtoml to #create-a-bootstraptoml)
 - #138854 (Fix ICE #138415 for invalid extern function body)
 - #138858 (Say which test failed the `COMPILETEST_REQUIRE_ALL_LLVM_COMPONENTS` assertion)
 - #138861 (Tweak type flags, fix missing flags from coroutine kind ty)

Failed merges:

 - #138755 ([rustdoc] Remove duplicated loop when computing doc cfgs)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-03-23 20:59:14 +00:00
commit 7290b04b0a
45 changed files with 674 additions and 223 deletions

View File

@ -1,7 +1,7 @@
# Sample TOML configuration file for building Rust.
#
# To configure bootstrap, run `./configure` or `./x.py setup`.
# See https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html#create-a-configtoml for more information.
# See https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html#create-a-bootstraptoml for more information.
#
# All options are commented out by default in this file, and they're commented
# out with their default values. The build system by default looks for
@ -446,7 +446,7 @@
# a specific version.
#ccache = false
# List of paths to exclude from the build and test processes.
# List of paths to exclude from the build and test processes.
# For example, exclude = ["tests/ui", "src/tools/tidy"].
#exclude = []

View File

@ -1724,8 +1724,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
return;
};
let define_opaque = define_opaque.iter().filter_map(|(id, path)| {
let res = self.resolver.get_partial_res(*id).unwrap();
let Some(did) = res.expect_full_res().opt_def_id() else {
let res = self.resolver.get_partial_res(*id);
let Some(did) = res.and_then(|res| res.expect_full_res().opt_def_id()) else {
self.dcx().span_delayed_bug(path.span, "should have errored in resolve");
return None;
};

View File

@ -20,7 +20,7 @@
// tidy-alphabetical-end
use std::cmp::max;
use std::collections::BTreeMap;
use std::collections::{BTreeMap, BTreeSet};
use std::ffi::OsString;
use std::fmt::Write as _;
use std::fs::{self, File};
@ -61,7 +61,7 @@ use rustc_session::config::{
};
use rustc_session::getopts::{self, Matches};
use rustc_session::lint::{Lint, LintId};
use rustc_session::output::collect_crate_types;
use rustc_session::output::{CRATE_TYPES, collect_crate_types, invalid_output_for_target};
use rustc_session::{EarlyDiagCtxt, Session, config, filesearch};
use rustc_span::FileName;
use rustc_target::json::ToJson;
@ -790,6 +790,16 @@ fn print_crate_info(
sess.dcx().fatal("only Apple targets currently support deployment version info")
}
}
SupportedCrateTypes => {
let supported_crate_types = CRATE_TYPES
.iter()
.filter(|(_, crate_type)| !invalid_output_for_target(&sess, *crate_type))
.map(|(crate_type_sym, _)| *crate_type_sym)
.collect::<BTreeSet<_>>();
for supported_crate_type in supported_crate_types {
println_info!("{}", supported_crate_type.as_str());
}
}
}
req.out.overwrite(&crate_info, sess);

View File

@ -101,63 +101,13 @@ impl FlagComputation {
&ty::Param(_) => {
self.add_flags(TypeFlags::HAS_TY_PARAM);
self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
}
ty::Coroutine(_, args) => {
let args = args.as_coroutine();
let should_remove_further_specializable =
!self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
self.add_args(args.parent_args());
if should_remove_further_specializable {
self.flags -= TypeFlags::STILL_FURTHER_SPECIALIZABLE;
}
self.add_ty(args.resume_ty());
self.add_ty(args.return_ty());
self.add_ty(args.witness());
self.add_ty(args.yield_ty());
self.add_ty(args.tupled_upvars_ty());
}
ty::CoroutineWitness(_, args) => {
let should_remove_further_specializable =
!self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
&ty::Closure(_, args)
| &ty::Coroutine(_, args)
| &ty::CoroutineClosure(_, args)
| &ty::CoroutineWitness(_, args) => {
self.add_args(args);
if should_remove_further_specializable {
self.flags -= TypeFlags::STILL_FURTHER_SPECIALIZABLE;
}
self.add_flags(TypeFlags::HAS_TY_COROUTINE);
}
&ty::Closure(_, args) => {
let args = args.as_closure();
let should_remove_further_specializable =
!self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
self.add_args(args.parent_args());
if should_remove_further_specializable {
self.flags -= TypeFlags::STILL_FURTHER_SPECIALIZABLE;
}
self.add_ty(args.sig_as_fn_ptr_ty());
self.add_ty(args.kind_ty());
self.add_ty(args.tupled_upvars_ty());
}
&ty::CoroutineClosure(_, args) => {
let args = args.as_coroutine_closure();
let should_remove_further_specializable =
!self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
self.add_args(args.parent_args());
if should_remove_further_specializable {
self.flags -= TypeFlags::STILL_FURTHER_SPECIALIZABLE;
}
self.add_ty(args.kind_ty());
self.add_ty(args.signature_parts_ty());
self.add_ty(args.tupled_upvars_ty());
self.add_ty(args.coroutine_captures_by_ref_ty());
self.add_ty(args.coroutine_witness_ty());
}
&ty::Bound(debruijn, _) => {
@ -167,21 +117,17 @@ impl FlagComputation {
&ty::Placeholder(..) => {
self.add_flags(TypeFlags::HAS_TY_PLACEHOLDER);
self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
}
&ty::Infer(infer) => {
self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
match infer {
ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => {
self.add_flags(TypeFlags::HAS_TY_FRESH)
}
ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => {
self.add_flags(TypeFlags::HAS_TY_INFER)
}
&ty::Infer(infer) => match infer {
ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => {
self.add_flags(TypeFlags::HAS_TY_FRESH)
}
}
ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => {
self.add_flags(TypeFlags::HAS_TY_INFER)
}
},
&ty::Adt(_, args) => {
self.add_args(args);
@ -358,24 +304,19 @@ impl FlagComputation {
self.add_args(uv.args);
self.add_flags(TypeFlags::HAS_CT_PROJECTION);
}
ty::ConstKind::Infer(infer) => {
self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
match infer {
InferConst::Fresh(_) => self.add_flags(TypeFlags::HAS_CT_FRESH),
InferConst::Var(_) => self.add_flags(TypeFlags::HAS_CT_INFER),
}
}
ty::ConstKind::Infer(infer) => match infer {
InferConst::Fresh(_) => self.add_flags(TypeFlags::HAS_CT_FRESH),
InferConst::Var(_) => self.add_flags(TypeFlags::HAS_CT_INFER),
},
ty::ConstKind::Bound(debruijn, _) => {
self.add_bound_var(debruijn);
self.add_flags(TypeFlags::HAS_CT_BOUND);
}
ty::ConstKind::Param(_) => {
self.add_flags(TypeFlags::HAS_CT_PARAM);
self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
}
ty::ConstKind::Placeholder(_) => {
self.add_flags(TypeFlags::HAS_CT_PLACEHOLDER);
self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
}
ty::ConstKind::Value(cv) => self.add_ty(cv.ty),
ty::ConstKind::Expr(e) => self.add_args(e.args()),

View File

@ -58,6 +58,7 @@ pub const PRINT_KINDS: &[(&str, PrintKind)] = &[
("relocation-models", PrintKind::RelocationModels),
("split-debuginfo", PrintKind::SplitDebuginfo),
("stack-protector-strategies", PrintKind::StackProtectorStrategies),
("supported-crate-types", PrintKind::SupportedCrateTypes),
("sysroot", PrintKind::Sysroot),
("target-cpus", PrintKind::TargetCPUs),
("target-features", PrintKind::TargetFeatures),
@ -888,6 +889,7 @@ pub enum PrintKind {
RelocationModels,
SplitDebuginfo,
StackProtectorStrategies,
SupportedCrateTypes,
Sysroot,
TargetCPUs,
TargetFeatures,
@ -2063,7 +2065,10 @@ fn check_print_request_stability(
(print_name, print_kind): (&str, PrintKind),
) {
match print_kind {
PrintKind::AllTargetSpecsJson | PrintKind::CheckCfg | PrintKind::TargetSpecJson
PrintKind::AllTargetSpecsJson
| PrintKind::CheckCfg
| PrintKind::SupportedCrateTypes
| PrintKind::TargetSpecJson
if !unstable_opts.unstable_options =>
{
early_dcx.early_fatal(format!(

View File

@ -111,18 +111,20 @@ bitflags::bitflags! {
/// Does this value have parameters/placeholders/inference variables which could be
/// replaced later, in a way that would change the results of `impl` specialization?
const STILL_FURTHER_SPECIALIZABLE = 1 << 21;
const STILL_FURTHER_SPECIALIZABLE = TypeFlags::HAS_TY_PARAM.bits()
| TypeFlags::HAS_TY_PLACEHOLDER.bits()
| TypeFlags::HAS_TY_INFER.bits()
| TypeFlags::HAS_CT_PARAM.bits()
| TypeFlags::HAS_CT_PLACEHOLDER.bits()
| TypeFlags::HAS_CT_INFER.bits();
/// Does this value have `InferTy::FreshTy/FreshIntTy/FreshFloatTy`?
const HAS_TY_FRESH = 1 << 22;
const HAS_TY_FRESH = 1 << 21;
/// Does this value have `InferConst::Fresh`?
const HAS_CT_FRESH = 1 << 23;
/// Does this have `Coroutine` or `CoroutineWitness`?
const HAS_TY_COROUTINE = 1 << 24;
const HAS_CT_FRESH = 1 << 22;
/// Does this have any binders with bound vars (e.g. that need to be anonymized)?
const HAS_BINDER_VARS = 1 << 25;
const HAS_BINDER_VARS = 1 << 23;
}
}

View File

@ -269,10 +269,6 @@ pub trait TypeVisitableExt<I: Interner>: TypeVisitable<I> {
self.has_type_flags(TypeFlags::HAS_TY_OPAQUE)
}
fn has_coroutines(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_TY_COROUTINE)
}
fn references_error(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_ERROR)
}

View File

@ -172,61 +172,6 @@ where
}
}
/// Marker trait for iterators/iterables which have a statically known upper
/// bound of the number of items they can produce.
///
/// # Safety
///
/// Implementations must not yield more elements than indicated by UPPER_BOUND if it is `Some`.
/// Used in specializations. Implementations must not be conditional on lifetimes or
/// user-implementable traits.
#[rustc_specialization_trait]
#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe trait BoundedSize {
const UPPER_BOUND: Option<NonZero<usize>> = NonZero::new(1);
}
#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<T> BoundedSize for Option<T> {}
#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<T> BoundedSize for option::IntoIter<T> {}
#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<T, U> BoundedSize for Result<T, U> {}
#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<T> BoundedSize for result::IntoIter<T> {}
#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<T> BoundedSize for Once<T> {}
#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<T> BoundedSize for OnceWith<T> {}
#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<T, const N: usize> BoundedSize for [T; N] {
const UPPER_BOUND: Option<NonZero<usize>> = NonZero::new(N);
}
#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<T, const N: usize> BoundedSize for array::IntoIter<T, N> {
const UPPER_BOUND: Option<NonZero<usize>> = NonZero::new(N);
}
#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<I: BoundedSize, P> BoundedSize for Filter<I, P> {
const UPPER_BOUND: Option<NonZero<usize>> = I::UPPER_BOUND;
}
#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<I: BoundedSize, P> BoundedSize for FilterMap<I, P> {
const UPPER_BOUND: Option<NonZero<usize>> = I::UPPER_BOUND;
}
#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<I: BoundedSize, F> BoundedSize for Map<I, F> {
const UPPER_BOUND: Option<NonZero<usize>> = I::UPPER_BOUND;
}
#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<I: BoundedSize> BoundedSize for Copied<I> {
const UPPER_BOUND: Option<NonZero<usize>> = I::UPPER_BOUND;
}
#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<I: BoundedSize> BoundedSize for Cloned<I> {
const UPPER_BOUND: Option<NonZero<usize>> = I::UPPER_BOUND;
}
/// An iterator that flattens one level of nesting in an iterator of things
/// that can be turned into iterators.
///

View File

@ -1744,7 +1744,7 @@ pub(crate) mod builtin {
}
/// Provide a list of type aliases and other opaque-type-containing type definitions.
/// This list will be used in the body of the item it is applied to to define opaque
/// This list will be used in the body of the item it is applied to define opaque
/// types' hidden types.
/// Can only be applied to things that have bodies.
#[unstable(

View File

@ -315,12 +315,8 @@ fn read_buf() {
let mut buf = BorrowedBuf::from(buf.as_mut_slice());
t!(s.read_buf(buf.unfilled()));
assert_eq!(buf.filled(), &[1, 2, 3, 4]);
// FIXME: sgx uses default_read_buf that initializes the buffer.
if cfg!(not(target_env = "sgx")) {
// TcpStream::read_buf should omit buffer initialization.
assert_eq!(buf.init_len(), 4);
}
// TcpStream::read_buf should omit buffer initialization.
assert_eq!(buf.init_len(), 4);
t.join().ok().expect("thread panicked");
})

View File

@ -36,7 +36,7 @@ pub struct FilePermissions(bool);
pub struct FileType(bool);
#[derive(Debug)]
pub struct DirBuilder {}
pub struct DirBuilder;
impl FileAttr {
pub fn size(&self) -> u64 {
@ -248,11 +248,11 @@ impl File {
impl DirBuilder {
pub fn new() -> DirBuilder {
DirBuilder {}
DirBuilder
}
pub fn mkdir(&self, _p: &Path) -> io::Result<()> {
unsupported()
pub fn mkdir(&self, p: &Path) -> io::Result<()> {
uefi_fs::mkdir(p)
}
}
@ -452,4 +452,30 @@ mod uefi_fs {
}
}
}
/// An implementation of mkdir to allow creating new directory without having to open the
/// volume twice (once for checking and once for creating)
pub(crate) fn mkdir(path: &Path) -> io::Result<()> {
let absolute = crate::path::absolute(path)?;
let p = helpers::OwnedDevicePath::from_text(absolute.as_os_str())?;
let (vol, mut path_remaining) = File::open_volume_from_device_path(p.borrow())?;
// Check if file exists
match vol.open(&mut path_remaining, file::MODE_READ, 0) {
Ok(_) => {
return Err(io::Error::new(io::ErrorKind::AlreadyExists, "Path already exists"));
}
Err(e) if e.kind() == io::ErrorKind::NotFound => {}
Err(e) => return Err(e),
}
let _ = vol.open(
&mut path_remaining,
file::MODE_READ | file::MODE_WRITE | file::MODE_CREATE,
file::DIRECTORY,
)?;
Ok(())
}
}

View File

@ -120,39 +120,6 @@ pub(crate) fn open_protocol<T>(
}
}
pub(crate) fn create_event(
signal: u32,
tpl: efi::Tpl,
handler: Option<efi::EventNotify>,
context: *mut crate::ffi::c_void,
) -> io::Result<NonNull<crate::ffi::c_void>> {
let boot_services: NonNull<efi::BootServices> =
boot_services().ok_or(BOOT_SERVICES_UNAVAILABLE)?.cast();
let mut event: r_efi::efi::Event = crate::ptr::null_mut();
let r = unsafe {
let create_event = (*boot_services.as_ptr()).create_event;
(create_event)(signal, tpl, handler, context, &mut event)
};
if r.is_error() {
Err(crate::io::Error::from_raw_os_error(r.as_usize()))
} else {
NonNull::new(event).ok_or(const_error!(io::ErrorKind::Other, "null protocol"))
}
}
/// # SAFETY
/// - The supplied event must be valid
pub(crate) unsafe fn close_event(evt: NonNull<crate::ffi::c_void>) -> io::Result<()> {
let boot_services: NonNull<efi::BootServices> =
boot_services().ok_or(BOOT_SERVICES_UNAVAILABLE)?.cast();
let r = unsafe {
let close_event = (*boot_services.as_ptr()).close_event;
(close_event)(evt.as_ptr())
};
if r.is_error() { Err(crate::io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) }
}
/// Gets the Protocol for current system handle.
///
/// Note: Some protocols need to be manually freed. It is the caller's responsibility to do so.
@ -735,3 +702,56 @@ impl Drop for ServiceProtocol {
}
}
}
#[repr(transparent)]
pub(crate) struct OwnedEvent(NonNull<crate::ffi::c_void>);
impl OwnedEvent {
pub(crate) fn new(
signal: u32,
tpl: efi::Tpl,
handler: Option<efi::EventNotify>,
context: Option<NonNull<crate::ffi::c_void>>,
) -> io::Result<Self> {
let boot_services: NonNull<efi::BootServices> =
boot_services().ok_or(BOOT_SERVICES_UNAVAILABLE)?.cast();
let mut event: r_efi::efi::Event = crate::ptr::null_mut();
let context = context.map(NonNull::as_ptr).unwrap_or(crate::ptr::null_mut());
let r = unsafe {
let create_event = (*boot_services.as_ptr()).create_event;
(create_event)(signal, tpl, handler, context, &mut event)
};
if r.is_error() {
Err(crate::io::Error::from_raw_os_error(r.as_usize()))
} else {
NonNull::new(event)
.ok_or(const_error!(io::ErrorKind::Other, "failed to create event"))
.map(Self)
}
}
pub(crate) fn into_raw(self) -> *mut crate::ffi::c_void {
let r = self.0.as_ptr();
crate::mem::forget(self);
r
}
/// SAFETY: Assumes that ptr is a non-null valid UEFI event
pub(crate) unsafe fn from_raw(ptr: *mut crate::ffi::c_void) -> Self {
Self(unsafe { NonNull::new_unchecked(ptr) })
}
}
impl Drop for OwnedEvent {
fn drop(&mut self) {
if let Some(boot_services) = boot_services() {
let bt: NonNull<r_efi::efi::BootServices> = boot_services.cast();
unsafe {
let close_event = (*bt.as_ptr()).close_event;
(close_event)(self.0.as_ptr())
};
}
}
}

View File

@ -46,17 +46,17 @@ pub(crate) unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {
unsafe { uefi::env::init_globals(image_handle, system_table) };
// Register exit boot services handler
match helpers::create_event(
match helpers::OwnedEvent::new(
r_efi::efi::EVT_SIGNAL_EXIT_BOOT_SERVICES,
r_efi::efi::TPL_NOTIFY,
Some(exit_boot_service_handler),
crate::ptr::null_mut(),
None,
) {
Ok(x) => {
if EXIT_BOOT_SERVICE_EVENT
.compare_exchange(
crate::ptr::null_mut(),
x.as_ptr(),
x.into_raw(),
Ordering::Release,
Ordering::Acquire,
)
@ -76,7 +76,7 @@ pub unsafe fn cleanup() {
if let Some(exit_boot_service_event) =
NonNull::new(EXIT_BOOT_SERVICE_EVENT.swap(crate::ptr::null_mut(), Ordering::Acquire))
{
let _ = unsafe { helpers::close_event(exit_boot_service_event) };
let _ = unsafe { helpers::OwnedEvent::from_raw(exit_boot_service_event.as_ptr()) };
}
}
@ -142,7 +142,7 @@ pub fn abort_internal() -> ! {
if let Some(exit_boot_service_event) =
NonNull::new(EXIT_BOOT_SERVICE_EVENT.load(Ordering::Acquire))
{
let _ = unsafe { helpers::close_event(exit_boot_service_event) };
let _ = unsafe { helpers::OwnedEvent::from_raw(exit_boot_service_event.as_ptr()) };
}
if let (Some(boot_services), Some(handle)) =

View File

@ -0,0 +1,27 @@
# `print=supported-crate-types`
The tracking issue for this feature is: [#138640](https://github.com/rust-lang/rust/issues/138640).
------------------------
This option of the `--print` flag produces a list of crate types (delimited by newlines) supported for the given target.
The crate type strings correspond to the values accepted by the `--crate-type` flag.
Intended to be used like this:
```bash
rustc --print=supported-crate-types -Zunstable-options --target=x86_64-unknown-linux-gnu
```
Example output for `x86_64-unknown-linux-gnu`:
```text
bin
cdylib
dylib
lib
proc-macro
rlib
staticlib
```

View File

@ -8,7 +8,6 @@ use std::{mem, ops};
use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit};
use rustc_data_structures::fx::FxHashSet;
use rustc_feature::Features;
use rustc_session::parse::ParseSess;
use rustc_span::Span;
use rustc_span::symbol::{Symbol, sym};
@ -132,18 +131,13 @@ impl Cfg {
/// Checks whether the given configuration can be matched in the current session.
///
/// Equivalent to `attr::cfg_matches`.
// FIXME: Actually make use of `features`.
pub(crate) fn matches(&self, psess: &ParseSess, features: Option<&Features>) -> bool {
pub(crate) fn matches(&self, psess: &ParseSess) -> bool {
match *self {
Cfg::False => false,
Cfg::True => true,
Cfg::Not(ref child) => !child.matches(psess, features),
Cfg::All(ref sub_cfgs) => {
sub_cfgs.iter().all(|sub_cfg| sub_cfg.matches(psess, features))
}
Cfg::Any(ref sub_cfgs) => {
sub_cfgs.iter().any(|sub_cfg| sub_cfg.matches(psess, features))
}
Cfg::Not(ref child) => !child.matches(psess),
Cfg::All(ref sub_cfgs) => sub_cfgs.iter().all(|sub_cfg| sub_cfg.matches(psess)),
Cfg::Any(ref sub_cfgs) => sub_cfgs.iter().any(|sub_cfg| sub_cfg.matches(psess)),
Cfg::Cfg(name, value) => psess.config.contains(&(name, value)),
}
}

View File

@ -1068,6 +1068,13 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute>
.meta_item()
.and_then(|item| rustc_expand::config::parse_cfg(item, sess))
{
// The result is unused here but we can gate unstable predicates
rustc_attr_parsing::cfg_matches(
cfg_mi,
tcx.sess,
rustc_ast::CRATE_NODE_ID,
Some(tcx.features()),
);
match Cfg::parse(cfg_mi) {
Ok(new_cfg) => cfg &= new_cfg,
Err(e) => {

View File

@ -98,7 +98,7 @@ impl HirCollector<'_> {
let ast_attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id));
if let Some(ref cfg) =
extract_cfg_from_attrs(ast_attrs.iter(), self.tcx, &FxHashSet::default())
&& !cfg.matches(&self.tcx.sess.psess, Some(self.tcx.features()))
&& !cfg.matches(&self.tcx.sess.psess)
{
return;
}

View File

@ -1385,7 +1385,7 @@ pub fn make_test_description<R: Read>(
decision!(cfg::handle_ignore(config, ln));
decision!(cfg::handle_only(config, ln));
decision!(needs::handle_needs(&cache.needs, config, ln));
decision!(ignore_llvm(config, ln));
decision!(ignore_llvm(config, path, ln));
decision!(ignore_cdb(config, ln));
decision!(ignore_gdb(config, ln));
decision!(ignore_lldb(config, ln));
@ -1525,7 +1525,7 @@ fn ignore_lldb(config: &Config, line: &str) -> IgnoreDecision {
IgnoreDecision::Continue
}
fn ignore_llvm(config: &Config, line: &str) -> IgnoreDecision {
fn ignore_llvm(config: &Config, path: &Path, line: &str) -> IgnoreDecision {
if let Some(needed_components) =
config.parse_name_value_directive(line, "needs-llvm-components")
{
@ -1536,8 +1536,9 @@ fn ignore_llvm(config: &Config, line: &str) -> IgnoreDecision {
{
if env::var_os("COMPILETEST_REQUIRE_ALL_LLVM_COMPONENTS").is_some() {
panic!(
"missing LLVM component {}, and COMPILETEST_REQUIRE_ALL_LLVM_COMPONENTS is set",
missing_component
"missing LLVM component {}, and COMPILETEST_REQUIRE_ALL_LLVM_COMPONENTS is set: {}",
missing_component,
path.display()
);
}
return IgnoreDecision::Ignore {

View File

@ -1,4 +1,3 @@
// skip-filecheck
//@ compile-flags: -O -Zmir-opt-level=2
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
@ -8,10 +7,48 @@
// EMIT_MIR checked_ops.step_forward.PreCodegen.after.mir
pub fn step_forward(x: u16, n: usize) -> u16 {
// This uses `u16` so that the conversion to usize is always widening.
// CHECK-LABEL: fn step_forward
// CHECK: inlined{{.+}}forward
std::iter::Step::forward(x, n)
}
// EMIT_MIR checked_ops.checked_shl.PreCodegen.after.mir
pub fn checked_shl(x: u32, rhs: u32) -> Option<u32> {
// CHECK-LABEL: fn checked_shl
// CHECK: [[TEMP:_[0-9]+]] = ShlUnchecked(copy _1, copy _2)
// CHECK: _0 = Option::<u32>::Some({{move|copy}} [[TEMP]])
x.checked_shl(rhs)
}
// EMIT_MIR checked_ops.use_checked_sub.PreCodegen.after.mir
pub fn use_checked_sub(x: u32, rhs: u32) {
// We want this to be equivalent to open-coding it, leaving no `Option`s around.
// FIXME(#138544): It's not yet.
// CHECK-LABEL: fn use_checked_sub
// CHECK: inlined{{.+}}u32{{.+}}checked_sub
// CHECK: [[DELTA:_[0-9]+]] = SubUnchecked(copy _1, copy _2)
// CHECK: [[TEMP1:_.+]] = Option::<u32>::Some(move [[DELTA]]);
// CHECK: [[TEMP2:_.+]] = {{move|copy}} (([[TEMP1]] as Some).0: u32);
// CHECK: do_something({{move|copy}} [[TEMP2]])
if let Some(delta) = x.checked_sub(rhs) {
do_something(delta);
}
}
// EMIT_MIR checked_ops.saturating_sub_at_home.PreCodegen.after.mir
pub fn saturating_sub_at_home(lhs: u32, rhs: u32) -> u32 {
// FIXME(#138544): Similarly here, the `Option` ought to optimize away
// CHECK-LABEL: fn saturating_sub_at_home
// CHECK: [[DELTA:_[0-9]+]] = SubUnchecked(copy _1, copy _2)
// CHECK: [[TEMP1:_.+]] = Option::<u32>::Some({{move|copy}} [[DELTA]]);
// CHECK: [[TEMP2:_.+]] = {{move|copy}} (([[TEMP1]] as Some).0: u32);
// CHECK: _0 = {{move|copy}} [[TEMP2]];
u32::checked_sub(lhs, rhs).unwrap_or(0)
}
unsafe extern "Rust" {
safe fn do_something(_: u32);
}

View File

@ -0,0 +1,48 @@
// MIR for `saturating_sub_at_home` after PreCodegen
fn saturating_sub_at_home(_1: u32, _2: u32) -> u32 {
debug lhs => _1;
debug rhs => _2;
let mut _0: u32;
let mut _5: std::option::Option<u32>;
scope 1 (inlined core::num::<impl u32>::checked_sub) {
let mut _3: bool;
let mut _4: u32;
}
scope 2 (inlined Option::<u32>::unwrap_or) {
let _6: u32;
scope 3 {
}
}
bb0: {
StorageLive(_5);
StorageLive(_3);
_3 = Lt(copy _1, copy _2);
switchInt(move _3) -> [0: bb1, otherwise: bb2];
}
bb1: {
StorageLive(_4);
_4 = SubUnchecked(copy _1, copy _2);
_5 = Option::<u32>::Some(move _4);
StorageDead(_4);
StorageDead(_3);
StorageLive(_6);
_6 = move ((_5 as Some).0: u32);
_0 = move _6;
StorageDead(_6);
goto -> bb3;
}
bb2: {
StorageDead(_3);
_0 = const 0_u32;
goto -> bb3;
}
bb3: {
StorageDead(_5);
return;
}
}

View File

@ -0,0 +1,48 @@
// MIR for `saturating_sub_at_home` after PreCodegen
fn saturating_sub_at_home(_1: u32, _2: u32) -> u32 {
debug lhs => _1;
debug rhs => _2;
let mut _0: u32;
let mut _5: std::option::Option<u32>;
scope 1 (inlined core::num::<impl u32>::checked_sub) {
let mut _3: bool;
let mut _4: u32;
}
scope 2 (inlined Option::<u32>::unwrap_or) {
let _6: u32;
scope 3 {
}
}
bb0: {
StorageLive(_5);
StorageLive(_3);
_3 = Lt(copy _1, copy _2);
switchInt(move _3) -> [0: bb1, otherwise: bb2];
}
bb1: {
StorageLive(_4);
_4 = SubUnchecked(copy _1, copy _2);
_5 = Option::<u32>::Some(move _4);
StorageDead(_4);
StorageDead(_3);
StorageLive(_6);
_6 = move ((_5 as Some).0: u32);
_0 = move _6;
StorageDead(_6);
goto -> bb3;
}
bb2: {
StorageDead(_3);
_0 = const 0_u32;
goto -> bb3;
}
bb3: {
StorageDead(_5);
return;
}
}

View File

@ -0,0 +1,44 @@
// MIR for `use_checked_sub` after PreCodegen
fn use_checked_sub(_1: u32, _2: u32) -> () {
debug x => _1;
debug rhs => _2;
let mut _0: ();
let mut _5: std::option::Option<u32>;
let _7: ();
scope 1 {
debug delta => _6;
let _6: u32;
scope 2 (inlined core::num::<impl u32>::checked_sub) {
let mut _3: bool;
let mut _4: u32;
}
}
bb0: {
StorageLive(_5);
StorageLive(_3);
_3 = Lt(copy _1, copy _2);
switchInt(move _3) -> [0: bb1, otherwise: bb2];
}
bb1: {
StorageLive(_4);
_4 = SubUnchecked(copy _1, copy _2);
_5 = Option::<u32>::Some(move _4);
StorageDead(_4);
StorageDead(_3);
_6 = copy ((_5 as Some).0: u32);
_7 = do_something(move _6) -> [return: bb3, unwind unreachable];
}
bb2: {
StorageDead(_3);
goto -> bb3;
}
bb3: {
StorageDead(_5);
return;
}
}

View File

@ -0,0 +1,44 @@
// MIR for `use_checked_sub` after PreCodegen
fn use_checked_sub(_1: u32, _2: u32) -> () {
debug x => _1;
debug rhs => _2;
let mut _0: ();
let mut _5: std::option::Option<u32>;
let _7: ();
scope 1 {
debug delta => _6;
let _6: u32;
scope 2 (inlined core::num::<impl u32>::checked_sub) {
let mut _3: bool;
let mut _4: u32;
}
}
bb0: {
StorageLive(_5);
StorageLive(_3);
_3 = Lt(copy _1, copy _2);
switchInt(move _3) -> [0: bb1, otherwise: bb2];
}
bb1: {
StorageLive(_4);
_4 = SubUnchecked(copy _1, copy _2);
_5 = Option::<u32>::Some(move _4);
StorageDead(_4);
StorageDead(_3);
_6 = copy ((_5 as Some).0: u32);
_7 = do_something(move _6) -> [return: bb3, unwind continue];
}
bb2: {
StorageDead(_3);
goto -> bb3;
}
bb3: {
StorageDead(_5);
return;
}
}

View File

@ -3,7 +3,7 @@
fn ezmap(_1: Option<i32>) -> Option<i32> {
debug x => _1;
let mut _0: std::option::Option<i32>;
scope 1 (inlined map::<i32, i32, {closure@$DIR/simple_option_map.rs:17:12: 17:15}>) {
scope 1 (inlined map::<i32, i32, {closure@$DIR/simple_option_map.rs:23:12: 23:15}>) {
let mut _2: isize;
let _3: i32;
let mut _4: i32;

View File

@ -0,0 +1,70 @@
// MIR for `map_via_question_mark` after PreCodegen
fn map_via_question_mark(_1: Option<i32>) -> Option<i32> {
debug x => _1;
let mut _0: std::option::Option<i32>;
let mut _4: std::ops::ControlFlow<std::option::Option<std::convert::Infallible>, i32>;
let _5: i32;
let mut _6: i32;
scope 1 {
debug residual => const Option::<Infallible>::None;
scope 2 {
scope 7 (inlined <Option<i32> as FromResidual<Option<Infallible>>>::from_residual) {
}
}
}
scope 3 {
debug val => _5;
scope 4 {
}
}
scope 5 (inlined <Option<i32> as Try>::branch) {
let mut _2: isize;
let _3: i32;
scope 6 {
}
}
bb0: {
StorageLive(_6);
StorageLive(_4);
StorageLive(_2);
StorageLive(_3);
_2 = discriminant(_1);
switchInt(move _2) -> [0: bb1, 1: bb2, otherwise: bb4];
}
bb1: {
StorageDead(_3);
StorageDead(_2);
_0 = const Option::<i32>::None;
StorageDead(_6);
StorageDead(_4);
goto -> bb3;
}
bb2: {
_3 = copy ((_1 as Some).0: i32);
_4 = ControlFlow::<Option<Infallible>, i32>::Continue(copy _3);
StorageDead(_3);
StorageDead(_2);
_5 = copy ((_4 as Continue).0: i32);
_6 = Add(copy _5, const 1_i32);
_0 = Option::<i32>::Some(move _6);
StorageDead(_6);
StorageDead(_4);
goto -> bb3;
}
bb3: {
return;
}
bb4: {
unreachable;
}
}
ALLOC0 (size: 8, align: 4) {
00 00 00 00 __ __ __ __ ....
}

View File

@ -1,7 +1,6 @@
// skip-filecheck
//@ compile-flags: -O -C debuginfo=0 -Zmir-opt-level=2
#[inline(always)]
#[inline]
fn map<T, U, F>(slf: Option<T>, f: F) -> Option<U>
where
F: FnOnce(T) -> U,
@ -14,9 +13,30 @@ where
// EMIT_MIR simple_option_map.ezmap.PreCodegen.after.mir
pub fn ezmap(x: Option<i32>) -> Option<i32> {
// We expect this to all be inlined, as though it was written without the
// combinator and without the closure, using just a plain match.
// CHECK-LABEL: fn ezmap
// CHECK: [[INNER:_.+]] = copy ((_1 as Some).0: i32);
// CHECK: [[SUCC:_.+]] = Add({{copy|move}} [[INNER]], const 1_i32);
// CHECK: _0 = Option::<i32>::Some({{copy|move}} [[SUCC]]);
map(x, |n| n + 1)
}
// EMIT_MIR simple_option_map.map_via_question_mark.PreCodegen.after.mir
pub fn map_via_question_mark(x: Option<i32>) -> Option<i32> {
// FIXME(#138544): Ideally this would optimize out the `ControlFlow` local.
// CHECK-LABEL: fn map_via_question_mark
// CHECK: [[INNER:_.+]] = copy ((_1 as Some).0: i32);
// CHECK: [[TEMP1:_.+]] = ControlFlow::<Option<Infallible>, i32>::Continue(copy [[INNER]]);
// CHECK: [[TEMP2:_.+]] = copy (([[TEMP1]] as Continue).0: i32);
// CHECK: [[SUCC:_.+]] = Add({{copy|move}} [[TEMP2]], const 1_i32);
// CHECK: _0 = Option::<i32>::Some({{copy|move}} [[SUCC]]);
Some(x? + 1)
}
fn main() {
assert_eq!(None, ezmap(None));
assert_eq!(None, map_via_question_mark(None));
}

View File

@ -29,7 +29,7 @@ Options:
--emit [asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]
Comma separated list of types of output for the
compiler to emit
--print [all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models]
--print [all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models]
Compiler information to print on stdout
-g Equivalent to -C debuginfo=2
-O Equivalent to -C opt-level=3

View File

@ -29,7 +29,7 @@ Options:
--emit [asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]
Comma separated list of types of output for the
compiler to emit
--print [all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models]
--print [all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models]
Compiler information to print on stdout
-g Equivalent to -C debuginfo=2
-O Equivalent to -C opt-level=3

View File

@ -0,0 +1,16 @@
// Ensure that `doc(cfg())` respects `check-cfg`
// Currently not properly working
#![feature(doc_cfg)]
#![deny(unexpected_cfgs)]
//@revisions: no_check cfg_empty cfg_foo
//@[cfg_empty] compile-flags: --check-cfg cfg()
//@[cfg_foo] compile-flags: --check-cfg cfg(foo)
//@[no_check] check-pass
//@[cfg_empty] check-pass
//@[cfg_empty] known-bug: #138358
//@[cfg_foo] check-pass
#[doc(cfg(foo))]
pub fn foo() {}

View File

@ -0,0 +1,10 @@
// #138113: rustdoc didn't gate unstable predicates inside `doc(cfg(..))`
#![feature(doc_cfg)]
// `cfg_boolean_literals`
#[doc(cfg(false))] //~ ERROR `cfg(false)` is experimental and subject to change
pub fn cfg_boolean_literals() {}
// `cfg_version`
#[doc(cfg(sanitize = "thread"))] //~ ERROR `cfg(sanitize)` is experimental and subject to change
pub fn cfg_sanitize() {}

View File

@ -0,0 +1,23 @@
error[E0658]: `cfg(false)` is experimental and subject to change
--> $DIR/doc-cfg-unstable.rs:5:11
|
LL | #[doc(cfg(false))]
| ^^^^^
|
= note: see issue #131204 <https://github.com/rust-lang/rust/issues/131204> for more information
= help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: `cfg(sanitize)` is experimental and subject to change
--> $DIR/doc-cfg-unstable.rs:9:11
|
LL | #[doc(cfg(sanitize = "thread"))]
| ^^^^^^^^^^^^^^^^^^^
|
= note: see issue #39699 <https://github.com/rust-lang/rust/issues/39699> for more information
= help: add `#![feature(cfg_sanitize)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0658`.

View File

@ -0,0 +1,12 @@
fn retry() -> impl Sized {}
struct Core<T>(T);
impl Core<XXX> { //~ ERROR cannot find type `XXX` in this scope
pub fn spawn(self) {}
}
fn main() {
let core = Core(1);
core.spawn(retry()); //~ ERROR this method takes 0 arguments but 1 argument was supplied
}

View File

@ -0,0 +1,32 @@
error[E0412]: cannot find type `XXX` in this scope
--> $DIR/trait-fn-generic-mismatch.rs:5:11
|
LL | impl Core<XXX> {
| ^^^ not found in this scope
|
help: you might be missing a type parameter
|
LL | impl<XXX> Core<XXX> {
| +++++
error[E0061]: this method takes 0 arguments but 1 argument was supplied
--> $DIR/trait-fn-generic-mismatch.rs:11:10
|
LL | core.spawn(retry());
| ^^^^^ ------- unexpected argument of type `impl Sized`
|
note: method defined here
--> $DIR/trait-fn-generic-mismatch.rs:6:12
|
LL | pub fn spawn(self) {}
| ^^^^^
help: remove the extra argument
|
LL - core.spawn(retry());
LL + core.spawn();
|
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0061, E0412.
For more information about an error, try `rustc --explain E0061`.

View File

@ -1,5 +1,5 @@
error: Argument to option 'print' missing
Usage:
--print [all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models]
--print [all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models]
Compiler information to print on stdout

View File

@ -1,5 +1,5 @@
error: unknown print request: `yyyy`
|
= help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `tls-models`
= help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `tls-models`
= help: for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information

View File

@ -0,0 +1,7 @@
//! Check that we point to `-Whelp` to guide the user to find the list of lints if the user requests
//! `--print=lints` (which is not a valid print request).
//@ compile-flags: --print lints
//@ error-pattern: error: unknown print request: `lints`
//@ error-pattern: help: use `-Whelp` to print a list of lints
//@ error-pattern: help: for more information, see the rustc book

View File

@ -1,6 +1,6 @@
error: unknown print request: `lints`
|
= help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `tls-models`
= help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `tls-models`
= help: use `-Whelp` to print a list of lints
= help: for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information

View File

@ -22,6 +22,10 @@
//@[check_cfg] compile-flags: --print=check-cfg
//@[check_cfg] error-pattern: the `-Z unstable-options` flag must also be passed
//@ revisions: supported_crate_types
//@[supported_crate_types] compile-flags: --print=supported-crate-types
//@[supported_crate_types] error-pattern: the `-Z unstable-options` flag must also be passed
//@ revisions: target_spec_json
//@[target_spec_json] compile-flags: --print=target-spec-json
//@[target_spec_json] error-pattern: the `-Z unstable-options` flag must also be passed

View File

@ -0,0 +1,7 @@
bin
cdylib
dylib
lib
proc-macro
rlib
staticlib

View File

@ -0,0 +1,5 @@
bin
lib
proc-macro
rlib
staticlib

View File

@ -0,0 +1,20 @@
//! Basic smoke test for `--print=supported-crate-types`, which should print a newline delimited
//! list of crate types supported by the given target. This test cherry-picks a few well-known
//! targets as examples.
//!
//! Tracking issue: <https://github.com/rust-lang/rust/issues/138640>
// ignore-tidy-linelength
//@ check-pass
//@ revisions: wasm musl linux
//@[wasm] compile-flags: --target=wasm32-unknown-unknown --print=supported-crate-types -Zunstable-options
//@[wasm] needs-llvm-components: webassembly
//@[musl] compile-flags: --target=x86_64-unknown-linux-musl --print=supported-crate-types -Zunstable-options
//@[musl] needs-llvm-components: x86
//@[linux] compile-flags: --target=x86_64-unknown-linux-gnu --print=supported-crate-types -Zunstable-options
//@[linux] needs-llvm-components: x86

View File

@ -0,0 +1,5 @@
bin
cdylib
lib
rlib
staticlib

View File

@ -1,2 +0,0 @@
//@ check-fail
//@ compile-flags: /dev/null --print lints

View File

@ -0,0 +1,11 @@
#![feature(type_alias_impl_trait)]
extern "C" {
fn a() {
//~^ ERROR incorrect function inside `extern` block
#[define_opaque(String)]
fn c() {}
}
}
pub fn main() {}

View File

@ -0,0 +1,20 @@
error: incorrect function inside `extern` block
--> $DIR/invalid-extern-fn-body.rs:4:8
|
LL | extern "C" {
| ---------- `extern` blocks define existing foreign functions and functions inside of them cannot have a body
LL | fn a() {
| ________^___-
| | |
| | cannot have a body
LL | |
LL | | #[define_opaque(String)]
LL | | fn c() {}
LL | | }
| |_____- help: remove the invalid body: `;`
|
= help: you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block
= note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
error: aborting due to 1 previous error