Auto merge of #113865 - Dylan-DPC:rollup-pt960bk, r=Dylan-DPC

Rollup of 7 pull requests

Successful merges:

 - #113444 (add tests for alias bound preference)
 - #113716 (Add the `no-builtins` attribute to functions when `no_builtins` is applied at the crate level.)
 - #113754 (Simplify native_libs query)
 - #113765 (Make it clearer that edition functions are `>=`, not `==`)
 - #113774 (Improve error message when closing bracket interpreted as formatting fill character)
 - #113785 (Fix invalid display of inlined re-export when both local and foreign items are inlined)
 - #113803 (Fix inline_const with interpolated block)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2023-07-19 18:17:59 +00:00
commit 39f42ad9e8
46 changed files with 425 additions and 193 deletions

View File

@ -335,6 +335,10 @@ pub fn from_fn_attrs<'ll, 'tcx>(
to_add.extend(probestack_attr(cx));
to_add.extend(stackprotector_attr(cx));
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_BUILTINS) {
to_add.push(llvm::CreateAttrString(cx.llcx, "no-builtins"));
}
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::COLD) {
to_add.push(AttributeKind::Cold.create_attr(cx.llcx));
}

View File

@ -1,4 +1,4 @@
use rustc_ast::{ast, MetaItemKind, NestedMetaItem};
use rustc_ast::{ast, attr, MetaItemKind, NestedMetaItem};
use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr};
use rustc_errors::struct_span_err;
use rustc_hir as hir;
@ -60,6 +60,14 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
}
// When `no_builtins` is applied at the crate level, we should add the
// `no-builtins` attribute to each function to ensure it takes effect in LTO.
let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
let no_builtins = attr::contains_name(crate_attrs, sym::no_builtins);
if no_builtins {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_BUILTINS;
}
let supported_target_features = tcx.supported_target_features(LOCAL_CRATE);
let mut inline_span = None;

View File

@ -1200,7 +1200,7 @@ fn check_matcher_core<'tt>(
err.span_label(sp, format!("not allowed after `{}` fragments", kind));
if kind == NonterminalKind::PatWithOr
&& sess.edition.rust_2021()
&& sess.edition.at_least_rust_2021()
&& next_token.is_token(&BinOp(token::BinOpToken::Or))
{
let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl(

View File

@ -86,7 +86,7 @@ pub(super) fn maybe_lint_bare_trait(&self, self_ty: &hir::Ty<'_>, in_path: bool)
));
}
if self_ty.span.edition().rust_2021() {
if self_ty.span.edition().at_least_rust_2021() {
let msg = "trait objects must include the `dyn` keyword";
let label = "add `dyn` keyword before this trait";
let mut diag =

View File

@ -860,7 +860,7 @@ pub fn resolve_ty_and_res_fully_qualified_call(
.resolve_fully_qualified_call(span, item_name, ty.normalized, qself.span, hir_id)
.and_then(|r| {
// lint bare trait if the method is found in the trait
if span.edition().rust_2021() && let Some(mut diag) = self.tcx.sess.diagnostic().steal_diagnostic(qself.span, StashKey::TraitMissingMethod) {
if span.edition().at_least_rust_2021() && let Some(mut diag) = self.tcx.sess.diagnostic().steal_diagnostic(qself.span, StashKey::TraitMissingMethod) {
diag.emit();
}
Ok(r)
@ -890,7 +890,7 @@ pub fn resolve_ty_and_res_fully_qualified_call(
}
// emit or cancel the diagnostic for bare traits
if span.edition().rust_2021() && let Some(mut diag) = self.tcx.sess.diagnostic().steal_diagnostic(qself.span, StashKey::TraitMissingMethod) {
if span.edition().at_least_rust_2021() && let Some(mut diag) = self.tcx.sess.diagnostic().steal_diagnostic(qself.span, StashKey::TraitMissingMethod) {
if trait_missing_method {
// cancel the diag for bare traits when meeting `MyTrait::missing_method`
diag.cancel();
@ -908,7 +908,7 @@ pub fn resolve_ty_and_res_fully_qualified_call(
error,
None,
Expectation::NoExpectation,
trait_missing_method && span.edition().rust_2021(), // emits missing method for trait only after edition 2021
trait_missing_method && span.edition().at_least_rust_2021(), // emits missing method for trait only after edition 2021
) {
e.emit();
}

View File

@ -32,7 +32,7 @@ pub(super) fn lint_dot_call_from_2018(
);
// Rust 2021 and later is already using the new prelude
if span.rust_2021() {
if span.at_least_rust_2021() {
return;
}
@ -203,7 +203,7 @@ pub(super) fn lint_fully_qualified_call_from_2018(
pick: &Pick<'tcx>,
) {
// Rust 2021 and later is already using the new prelude
if span.rust_2021() {
if span.at_least_rust_2021() {
return;
}

View File

@ -437,7 +437,7 @@ fn probe_op<OP, R>(
// this case used to be allowed by the compiler,
// so we do a future-compat lint here for the 2015 edition
// (see https://github.com/rust-lang/rust/issues/46906)
if self.tcx.sess.rust_2018() {
if self.tcx.sess.at_least_rust_2018() {
self.tcx.sess.emit_err(MethodCallOnUnknownRawPointee { span });
} else {
self.tcx.struct_span_lint_hir(
@ -1592,7 +1592,7 @@ fn consider_probe(
if let Some(method_name) = self.method_name {
// Some trait methods are excluded for arrays before 2021.
// (`array.into_iter()` wants a slice iterator for compatibility.)
if self_ty.is_array() && !method_name.span.rust_2021() {
if self_ty.is_array() && !method_name.span.at_least_rust_2021() {
let trait_def = self.tcx.trait_def(trait_ref.def_id);
if trait_def.skip_array_during_method_dispatch {
return ProbeResult::NoMatch;

View File

@ -2001,7 +2001,7 @@ fn should_do_rust_2021_incompatible_closure_captures_analysis(
tcx: TyCtxt<'_>,
closure_id: hir::HirId,
) -> bool {
if tcx.sess.rust_2021() {
if tcx.sess.at_least_rust_2021() {
return false;
}
@ -2247,5 +2247,5 @@ fn truncate_capture_for_optimization(
fn enable_precise_capture(span: Span) -> bool {
// We use span here to ensure that if the closure was generated by a macro with a different
// edition.
span.rust_2021()
span.at_least_rust_2021()
}

View File

@ -1,19 +1,28 @@
use rustc_data_structures::fx::FxIndexMap;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
use rustc_middle::query::LocalCrate;
use rustc_middle::ty::TyCtxt;
use rustc_session::cstore::ForeignModule;
pub(crate) fn collect(tcx: TyCtxt<'_>) -> Vec<ForeignModule> {
let mut modules = Vec::new();
pub(crate) fn collect(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> FxIndexMap<DefId, ForeignModule> {
let mut modules = FxIndexMap::default();
// We need to collect all the `ForeignMod`, even if they are empty.
for id in tcx.hir().items() {
if !matches!(tcx.def_kind(id.owner_id), DefKind::ForeignMod) {
continue;
}
let def_id = id.owner_id.to_def_id();
let item = tcx.hir().item(id);
if let hir::ItemKind::ForeignMod { items, .. } = item.kind {
if let hir::ItemKind::ForeignMod { abi, items } = item.kind {
let foreign_items = items.iter().map(|it| it.id.owner_id.to_def_id()).collect();
modules.push(ForeignModule { foreign_items, def_id: id.owner_id.to_def_id() });
modules.insert(def_id, ForeignModule { def_id, abi, foreign_items });
}
}
modules
}

View File

@ -1,15 +1,17 @@
use rustc_ast::{NestedMetaItem, CRATE_NODE_ID};
use rustc_attr as attr;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_middle::query::LocalCrate;
use rustc_middle::ty::{List, ParamEnv, ParamEnvAnd, Ty, TyCtxt};
use rustc_session::config::CrateType;
use rustc_session::cstore::{DllCallingConvention, DllImport, NativeLib, PeImportNameType};
use rustc_session::cstore::{
DllCallingConvention, DllImport, ForeignModule, NativeLib, PeImportNameType,
};
use rustc_session::parse::feature_err;
use rustc_session::search_paths::PathKind;
use rustc_session::utils::NativeLibKind;
use rustc_session::Session;
use rustc_span::def_id::{DefId, LOCAL_CRATE};
use rustc_span::symbol::{sym, Symbol};
use rustc_target::spec::abi::Abi;
@ -66,10 +68,12 @@ fn find_bundled_library(
None
}
pub(crate) fn collect(tcx: TyCtxt<'_>) -> Vec<NativeLib> {
pub(crate) fn collect(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> Vec<NativeLib> {
let mut collector = Collector { tcx, libs: Vec::new() };
for id in tcx.hir().items() {
collector.process_item(id);
if tcx.sess.opts.unstable_opts.link_directives {
for module in tcx.foreign_modules(LOCAL_CRATE).values() {
collector.process_module(module);
}
}
collector.process_command_line();
collector.libs
@ -88,29 +92,20 @@ struct Collector<'tcx> {
}
impl<'tcx> Collector<'tcx> {
fn process_item(&mut self, id: rustc_hir::ItemId) {
if !matches!(self.tcx.def_kind(id.owner_id), DefKind::ForeignMod) {
return;
}
fn process_module(&mut self, module: &ForeignModule) {
let ForeignModule { def_id, abi, ref foreign_items } = *module;
let def_id = def_id.expect_local();
let it = self.tcx.hir().item(id);
let hir::ItemKind::ForeignMod { abi, items: foreign_mod_items } = it.kind else {
return;
};
let sess = self.tcx.sess;
if matches!(abi, Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic) {
return;
}
// Process all of the #[link(..)]-style arguments
let sess = self.tcx.sess;
let features = self.tcx.features();
if !sess.opts.unstable_opts.link_directives {
return;
}
for m in self.tcx.hir().attrs(it.hir_id()).iter().filter(|a| a.has_name(sym::link)) {
for m in self.tcx.get_attrs(def_id, sym::link) {
let Some(items) = m.meta_item_list() else {
continue;
};
@ -340,9 +335,9 @@ fn process_item(&mut self, id: rustc_hir::ItemId) {
if name.as_str().contains('\0') {
sess.emit_err(errors::RawDylibNoNul { span: name_span });
}
foreign_mod_items
foreign_items
.iter()
.map(|child_item| {
.map(|&child_item| {
self.build_dll_import(
abi,
import_name_type.map(|(import_name_type, _)| import_name_type),
@ -352,21 +347,12 @@ fn process_item(&mut self, id: rustc_hir::ItemId) {
.collect()
}
_ => {
for child_item in foreign_mod_items {
if self.tcx.def_kind(child_item.id.owner_id).has_codegen_attrs()
&& self
.tcx
.codegen_fn_attrs(child_item.id.owner_id)
.link_ordinal
.is_some()
for &child_item in foreign_items {
if self.tcx.def_kind(child_item).has_codegen_attrs()
&& self.tcx.codegen_fn_attrs(child_item).link_ordinal.is_some()
{
let link_ordinal_attr = self
.tcx
.hir()
.attrs(child_item.id.owner_id.into())
.iter()
.find(|a| a.has_name(sym::link_ordinal))
.unwrap();
let link_ordinal_attr =
self.tcx.get_attr(child_item, sym::link_ordinal).unwrap();
sess.emit_err(errors::LinkOrdinalRawDylib {
span: link_ordinal_attr.span,
});
@ -384,7 +370,7 @@ fn process_item(&mut self, id: rustc_hir::ItemId) {
filename,
kind,
cfg,
foreign_module: Some(it.owner_id.to_def_id()),
foreign_module: Some(def_id.to_def_id()),
verbatim,
dll_imports,
});
@ -476,10 +462,10 @@ fn process_command_line(&mut self) {
}
}
fn i686_arg_list_size(&self, item: &hir::ForeignItemRef) -> usize {
fn i686_arg_list_size(&self, item: DefId) -> usize {
let argument_types: &List<Ty<'_>> = self.tcx.erase_late_bound_regions(
self.tcx
.type_of(item.id.owner_id)
.type_of(item)
.instantiate_identity()
.fn_sig(self.tcx)
.inputs()
@ -505,8 +491,10 @@ fn build_dll_import(
&self,
abi: Abi,
import_name_type: Option<PeImportNameType>,
item: &hir::ForeignItemRef,
item: DefId,
) -> DllImport {
let span = self.tcx.def_span(item);
let calling_convention = if self.tcx.sess.target.arch == "x86" {
match abi {
Abi::C { .. } | Abi::Cdecl { .. } => DllCallingConvention::C,
@ -520,29 +508,29 @@ fn build_dll_import(
DllCallingConvention::Vectorcall(self.i686_arg_list_size(item))
}
_ => {
self.tcx.sess.emit_fatal(errors::UnsupportedAbiI686 { span: item.span });
self.tcx.sess.emit_fatal(errors::UnsupportedAbiI686 { span });
}
}
} else {
match abi {
Abi::C { .. } | Abi::Win64 { .. } | Abi::System { .. } => DllCallingConvention::C,
_ => {
self.tcx.sess.emit_fatal(errors::UnsupportedAbi { span: item.span });
self.tcx.sess.emit_fatal(errors::UnsupportedAbi { span });
}
}
};
let codegen_fn_attrs = self.tcx.codegen_fn_attrs(item.id.owner_id);
let codegen_fn_attrs = self.tcx.codegen_fn_attrs(item);
let import_name_type = codegen_fn_attrs
.link_ordinal
.map_or(import_name_type, |ord| Some(PeImportNameType::Ordinal(ord)));
DllImport {
name: codegen_fn_attrs.link_name.unwrap_or(item.ident.name),
name: codegen_fn_attrs.link_name.unwrap_or(self.tcx.item_name(item)),
import_name_type,
calling_convention,
span: item.span,
is_fn: self.tcx.def_kind(item.id.owner_id).is_fn_like(),
span,
is_fn: self.tcx.def_kind(item).is_fn_like(),
}
}
}

View File

@ -403,10 +403,8 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
.contains(&id)
})
},
native_libraries: |tcx, LocalCrate| native_libs::collect(tcx),
foreign_modules: |tcx, LocalCrate| {
foreign_modules::collect(tcx).into_iter().map(|m| (m.def_id, m)).collect()
},
native_libraries: native_libs::collect,
foreign_modules: foreign_modules::collect,
// Returns a map from a sufficiently visible external item (i.e., an
// external item that is visible from at least one local module) to a

View File

@ -100,6 +100,8 @@ pub struct CodegenFnAttrFlags: u32 {
const REALLOCATOR = 1 << 18;
/// `#[rustc_allocator_zeroed]`: a hint to LLVM that the function only allocates zeroed memory.
const ALLOCATOR_ZEROED = 1 << 19;
/// `#[no_builtins]`: indicates that disable implicit builtin knowledge of functions for the function.
const NO_BUILTINS = 1 << 20;
}
}

View File

@ -1579,7 +1579,7 @@
}
/// Returns a list of all `extern` blocks of a crate.
query foreign_modules(_: CrateNum) -> &'tcx FxHashMap<DefId, ForeignModule> {
query foreign_modules(_: CrateNum) -> &'tcx FxIndexMap<DefId, ForeignModule> {
arena_cache
desc { "looking up the foreign modules of a linked crate" }
separate_provide_extern

View File

@ -1932,7 +1932,7 @@ fn print_const(self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
self.empty_path = true;
if cnum == LOCAL_CRATE {
if self.tcx.sess.rust_2018() {
if self.tcx.sess.at_least_rust_2018() {
// We add the `crate::` keyword on Rust 2018, only when desired.
if SHOULD_PREFIX_WITH_CRATE.with(|flag| flag.get()) {
write!(self, "{}", kw::Crate)?;

View File

@ -730,5 +730,5 @@ fn read_fake_borrows(
/// Precise capture is enabled if user is using Rust Edition 2021 or higher.
fn enable_precise_capture(closure_span: Span) -> bool {
closure_span.rust_2021()
closure_span.at_least_rust_2021()
}

View File

@ -1309,7 +1309,7 @@ fn parse_expr_index(&mut self, lo: Span, base: P<Expr>) -> PResult<'a, P<Expr>>
/// Assuming we have just parsed `.`, continue parsing into an expression.
fn parse_dot_suffix(&mut self, self_arg: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> {
if self.token.uninterpolated_span().rust_2018() && self.eat_keyword(kw::Await) {
if self.token.uninterpolated_span().at_least_rust_2018() && self.eat_keyword(kw::Await) {
return Ok(self.mk_await_expr(self_arg, lo));
}
@ -1442,8 +1442,8 @@ fn parse_expr_bottom(&mut self) -> PResult<'a, P<Expr>> {
self.parse_expr_let()
} else if self.eat_keyword(kw::Underscore) {
Ok(self.mk_expr(self.prev_token.span, ExprKind::Underscore))
} else if self.token.uninterpolated_span().rust_2018() {
// `Span::rust_2018()` is somewhat expensive; don't get it repeatedly.
} else if self.token.uninterpolated_span().at_least_rust_2018() {
// `Span:.at_least_rust_2018()` is somewhat expensive; don't get it repeatedly.
if self.check_keyword(kw::Async) {
if self.is_async_block() {
// Check for `async {` and `async move {`.
@ -2230,7 +2230,7 @@ fn parse_expr_closure(&mut self) -> PResult<'a, P<Expr>> {
let movability =
if self.eat_keyword(kw::Static) { Movability::Static } else { Movability::Movable };
let asyncness = if self.token.uninterpolated_span().rust_2018() {
let asyncness = if self.token.uninterpolated_span().at_least_rust_2018() {
self.parse_asyncness(Case::Sensitive)
} else {
Async::No
@ -3014,7 +3014,7 @@ fn is_do_yeet(&self) -> bool {
fn is_try_block(&self) -> bool {
self.token.is_keyword(kw::Try)
&& self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace))
&& self.token.uninterpolated_span().rust_2018()
&& self.token.uninterpolated_span().at_least_rust_2018()
}
/// Parses an `async move? {...}` expression.

View File

@ -1210,7 +1210,8 @@ fn parse_closure_constness(&mut self) -> Const {
fn parse_constness_(&mut self, case: Case, is_closure: bool) -> Const {
// Avoid const blocks and const closures to be parsed as const items
if (self.check_const_closure() == is_closure)
&& self.look_ahead(1, |t| t != &token::OpenDelim(Delimiter::Brace))
&& !self
.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block())
&& self.eat_keyword_case(kw::Const, case)
{
Const::Yes(self.prev_token.uninterpolated_span())

View File

@ -608,7 +608,7 @@ fn parse_impl_ty(&mut self, impl_dyn_multi: &mut bool) -> PResult<'a, TyKind> {
/// Is a `dyn B0 + ... + Bn` type allowed here?
fn is_explicit_dyn_type(&mut self) -> bool {
self.check_keyword(kw::Dyn)
&& (self.token.uninterpolated_span().rust_2018()
&& (self.token.uninterpolated_span().at_least_rust_2018()
|| self.look_ahead(1, |t| {
(t.can_begin_bound() || t.kind == TokenKind::BinOp(token::Star))
&& !can_continue_type_after_non_fn_ident(t)

View File

@ -109,6 +109,8 @@ pub struct Argument<'a> {
pub struct FormatSpec<'a> {
/// Optionally specified character to fill alignment with.
pub fill: Option<char>,
/// Span of the optionally specified fill character.
pub fill_span: Option<InnerSpan>,
/// Optionally specified alignment.
pub align: Alignment,
/// The `+` or `-` flag.
@ -264,7 +266,7 @@ fn next(&mut self) -> Option<Piece<'a>> {
Some(String(self.string(pos + 1)))
} else {
let arg = self.argument(lbrace_end);
if let Some(rbrace_pos) = self.must_consume('}') {
if let Some(rbrace_pos) = self.consume_closing_brace(&arg) {
if self.is_source_literal {
let lbrace_byte_pos = self.to_span_index(pos);
let rbrace_byte_pos = self.to_span_index(rbrace_pos);
@ -450,69 +452,51 @@ fn span(&self, start_pos: usize, end_pos: usize) -> InnerSpan {
/// Forces consumption of the specified character. If the character is not
/// found, an error is emitted.
fn must_consume(&mut self, c: char) -> Option<usize> {
fn consume_closing_brace(&mut self, arg: &Argument<'_>) -> Option<usize> {
self.ws();
if let Some(&(pos, maybe)) = self.cur.peek() {
if c == maybe {
let pos;
let description;
if let Some(&(peek_pos, maybe)) = self.cur.peek() {
if maybe == '}' {
self.cur.next();
Some(pos)
} else {
let pos = self.to_span_index(pos);
let description = format!("expected `'}}'`, found `{maybe:?}`");
let label = "expected `}`".to_owned();
let (note, secondary_label) = if c == '}' {
(
Some(
"if you intended to print `{`, you can escape it using `{{`".to_owned(),
),
self.last_opening_brace
.map(|sp| ("because of this opening brace".to_owned(), sp)),
)
} else {
(None, None)
};
self.errors.push(ParseError {
description,
note,
label,
span: pos.to(pos),
secondary_label,
should_be_replaced_with_positional_argument: false,
});
None
return Some(peek_pos);
}
pos = peek_pos;
description = format!("expected `'}}'`, found `{maybe:?}`");
} else {
let description = format!("expected `{c:?}` but string was terminated");
description = "expected `'}'` but string was terminated".to_owned();
// point at closing `"`
let pos = self.input.len() - if self.append_newline { 1 } else { 0 };
let pos = self.to_span_index(pos);
if c == '}' {
let label = format!("expected `{c:?}`");
let (note, secondary_label) = if c == '}' {
(
Some(
"if you intended to print `{`, you can escape it using `{{`".to_owned(),
),
self.last_opening_brace
.map(|sp| ("because of this opening brace".to_owned(), sp)),
)
} else {
(None, None)
};
self.errors.push(ParseError {
description,
note,
label,
span: pos.to(pos),
secondary_label,
should_be_replaced_with_positional_argument: false,
});
} else {
self.err(description, format!("expected `{c:?}`"), pos.to(pos));
}
None
pos = self.input.len() - if self.append_newline { 1 } else { 0 };
}
let pos = self.to_span_index(pos);
let label = "expected `'}'`".to_owned();
let (note, secondary_label) = if arg.format.fill == Some('}') {
(
Some("the character `'}'` is interpreted as a fill character because of the `:` that precedes it".to_owned()),
arg.format.fill_span.map(|sp| ("this is not interpreted as a formatting closing brace".to_owned(), sp)),
)
} else {
(
Some("if you intended to print `{`, you can escape it using `{{`".to_owned()),
self.last_opening_brace.map(|sp| ("because of this opening brace".to_owned(), sp)),
)
};
self.errors.push(ParseError {
description,
note,
label,
span: pos.to(pos),
secondary_label,
should_be_replaced_with_positional_argument: false,
});
None
}
/// Consumes all whitespace characters until the first non-whitespace character
@ -608,6 +592,7 @@ fn current_pos(&mut self) -> usize {
fn format(&mut self) -> FormatSpec<'a> {
let mut spec = FormatSpec {
fill: None,
fill_span: None,
align: AlignUnknown,
sign: None,
alternate: false,
@ -625,9 +610,10 @@ fn format(&mut self) -> FormatSpec<'a> {
}
// fill character
if let Some(&(_, c)) = self.cur.peek() {
if let Some(&(idx, c)) = self.cur.peek() {
if let Some((_, '>' | '<' | '^')) = self.cur.clone().nth(1) {
spec.fill = Some(c);
spec.fill_span = Some(self.span(idx, idx + 1));
self.cur.next();
}
}
@ -722,6 +708,7 @@ fn format(&mut self) -> FormatSpec<'a> {
fn inline_asm(&mut self) -> FormatSpec<'a> {
let mut spec = FormatSpec {
fill: None,
fill_span: None,
align: AlignUnknown,
sign: None,
alternate: false,

View File

@ -9,6 +9,7 @@ fn same(fmt: &'static str, p: &[Piece<'static>]) {
fn fmtdflt() -> FormatSpec<'static> {
return FormatSpec {
fill: None,
fill_span: None,
align: AlignUnknown,
sign: None,
alternate: false,
@ -128,6 +129,7 @@ fn format_type() {
position_span: InnerSpan { start: 2, end: 3 },
format: FormatSpec {
fill: None,
fill_span: None,
align: AlignUnknown,
sign: None,
alternate: false,
@ -152,6 +154,7 @@ fn format_align_fill() {
position_span: InnerSpan { start: 2, end: 3 },
format: FormatSpec {
fill: None,
fill_span: None,
align: AlignRight,
sign: None,
alternate: false,
@ -173,6 +176,7 @@ fn format_align_fill() {
position_span: InnerSpan { start: 2, end: 3 },
format: FormatSpec {
fill: Some('0'),
fill_span: Some(InnerSpan::new(4, 5)),
align: AlignLeft,
sign: None,
alternate: false,
@ -194,6 +198,7 @@ fn format_align_fill() {
position_span: InnerSpan { start: 2, end: 3 },
format: FormatSpec {
fill: Some('*'),
fill_span: Some(InnerSpan::new(4, 5)),
align: AlignLeft,
sign: None,
alternate: false,
@ -218,6 +223,7 @@ fn format_counts() {
position_span: InnerSpan { start: 2, end: 2 },
format: FormatSpec {
fill: None,
fill_span: None,
align: AlignUnknown,
sign: None,
alternate: false,
@ -239,6 +245,7 @@ fn format_counts() {
position_span: InnerSpan { start: 2, end: 2 },
format: FormatSpec {
fill: None,
fill_span: None,
align: AlignUnknown,
sign: None,
alternate: false,
@ -260,6 +267,7 @@ fn format_counts() {
position_span: InnerSpan { start: 2, end: 3 },
format: FormatSpec {
fill: None,
fill_span: None,
align: AlignUnknown,
sign: None,
alternate: false,
@ -281,6 +289,7 @@ fn format_counts() {
position_span: InnerSpan { start: 2, end: 2 },
format: FormatSpec {
fill: None,
fill_span: None,
align: AlignUnknown,
sign: None,
alternate: false,
@ -302,6 +311,7 @@ fn format_counts() {
position_span: InnerSpan { start: 2, end: 2 },
format: FormatSpec {
fill: None,
fill_span: None,
align: AlignUnknown,
sign: None,
alternate: false,
@ -323,6 +333,7 @@ fn format_counts() {
position_span: InnerSpan { start: 2, end: 2 },
format: FormatSpec {
fill: None,
fill_span: None,
align: AlignUnknown,
sign: None,
alternate: false,
@ -344,6 +355,7 @@ fn format_counts() {
position_span: InnerSpan { start: 2, end: 2 },
format: FormatSpec {
fill: None,
fill_span: None,
align: AlignUnknown,
sign: None,
alternate: false,
@ -368,6 +380,7 @@ fn format_flags() {
position_span: InnerSpan { start: 2, end: 2 },
format: FormatSpec {
fill: None,
fill_span: None,
align: AlignUnknown,
sign: Some(Sign::Minus),
alternate: false,
@ -389,6 +402,7 @@ fn format_flags() {
position_span: InnerSpan { start: 2, end: 2 },
format: FormatSpec {
fill: None,
fill_span: None,
align: AlignUnknown,
sign: Some(Sign::Plus),
alternate: true,
@ -415,6 +429,7 @@ fn format_mixture() {
position_span: InnerSpan { start: 7, end: 8 },
format: FormatSpec {
fill: None,
fill_span: None,
align: AlignUnknown,
sign: None,
alternate: false,

View File

@ -440,7 +440,7 @@ pub(crate) fn check_unused(&mut self, krate: &ast::Crate) {
// If we are not in Rust 2018 edition, then we don't make any further
// suggestions.
if !tcx.sess.rust_2018() {
if !tcx.sess.at_least_rust_2018() {
continue;
}

View File

@ -1203,7 +1203,7 @@ fn lookup_import_candidates_from_module<FilterFn>(
if filter_fn(res) {
// create the path
let mut segms = path_segments.clone();
if lookup_ident.span.rust_2018() {
if lookup_ident.span.at_least_rust_2018() {
// crate-local absolute paths start with `crate::` in edition 2018
// FIXME: may also be stabilized for Rust 2015 (Issues #45477, #44660)
segms.insert(0, ast::PathSegment::from_ident(crate_name));
@ -1268,7 +1268,7 @@ fn lookup_import_candidates_from_module<FilterFn>(
path_segments.push(ast::PathSegment::from_ident(ident));
let is_extern_crate_that_also_appears_in_prelude =
name_binding.is_extern_crate() && lookup_ident.span.rust_2018();
name_binding.is_extern_crate() && lookup_ident.span.at_least_rust_2018();
if !is_extern_crate_that_also_appears_in_prelude {
// add the module to the lookup
@ -1315,7 +1315,7 @@ pub(crate) fn lookup_import_candidates<FilterFn>(
&filter_fn,
);
if lookup_ident.span.rust_2018() {
if lookup_ident.span.at_least_rust_2018() {
let extern_prelude_names = self.extern_prelude.clone();
for (ident, _) in extern_prelude_names.into_iter() {
if ident.span.from_expansion() {
@ -1568,7 +1568,7 @@ fn report_ambiguity_error(&self, ambiguity_error: &AmbiguityError<'_>) {
"consider adding an explicit import of `{ident}` to disambiguate"
))
}
if b.is_extern_crate() && ident.span.rust_2018() {
if b.is_extern_crate() && ident.span.at_least_rust_2018() {
help_msgs.push(format!("use `::{ident}` to refer to this {thing} unambiguously"))
}
match misc {
@ -1973,7 +1973,7 @@ pub(crate) fn make_path_suggestion(
if fst.ident.name == kw::PathRoot && !snd.ident.is_path_segment_keyword() => {}
// `ident::...` on 2018.
(Some(fst), _)
if fst.ident.span.rust_2018() && !fst.ident.is_path_segment_keyword() =>
if fst.ident.span.at_least_rust_2018() && !fst.ident.is_path_segment_keyword() =>
{
// Insert a placeholder that's later replaced by `self`/`super`/etc.
path.insert(0, Segment::from_ident(Ident::empty()));

View File

@ -1417,13 +1417,13 @@ pub(crate) fn resolve_path_with_ribs(
));
continue;
}
if name == kw::PathRoot && ident.span.rust_2018() {
if name == kw::PathRoot && ident.span.at_least_rust_2018() {
module = Some(ModuleOrUniformRoot::ExternPrelude);
continue;
}
if name == kw::PathRoot
&& ident.span.is_rust_2015()
&& self.tcx.sess.rust_2018()
&& self.tcx.sess.at_least_rust_2018()
{
// `::a::b` from 2015 macro on 2018 global edition
module = Some(ModuleOrUniformRoot::CrateRootAndExternPrelude);

View File

@ -13,6 +13,7 @@
use rustc_span::hygiene::{ExpnHash, ExpnId};
use rustc_span::symbol::Symbol;
use rustc_span::Span;
use rustc_target::spec::abi::Abi;
use rustc_target::spec::Target;
use std::any::Any;
@ -147,6 +148,7 @@ pub enum DllCallingConvention {
pub struct ForeignModule {
pub foreign_items: Vec<DefId>,
pub def_id: DefId,
pub abi: Abi,
}
#[derive(Copy, Clone, Debug, HashStable_Generic)]

View File

@ -995,18 +995,18 @@ pub fn is_rust_2015(&self) -> bool {
}
/// Are we allowed to use features from the Rust 2018 edition?
pub fn rust_2018(&self) -> bool {
self.edition().rust_2018()
pub fn at_least_rust_2018(&self) -> bool {
self.edition().at_least_rust_2018()
}
/// Are we allowed to use features from the Rust 2021 edition?
pub fn rust_2021(&self) -> bool {
self.edition().rust_2021()
pub fn at_least_rust_2021(&self) -> bool {
self.edition().at_least_rust_2021()
}
/// Are we allowed to use features from the Rust 2024 edition?
pub fn rust_2024(&self) -> bool {
self.edition().rust_2024()
pub fn at_least_rust_2024(&self) -> bool {
self.edition().at_least_rust_2024()
}
/// Returns `true` if we should use the PLT for shared library calls.

View File

@ -82,17 +82,17 @@ pub fn is_rust_2015(self) -> bool {
}
/// Are we allowed to use features from the Rust 2018 edition?
pub fn rust_2018(self) -> bool {
pub fn at_least_rust_2018(self) -> bool {
self >= Edition::Edition2018
}
/// Are we allowed to use features from the Rust 2021 edition?
pub fn rust_2021(self) -> bool {
pub fn at_least_rust_2021(self) -> bool {
self >= Edition::Edition2021
}
/// Are we allowed to use features from the Rust 2024 edition?
pub fn rust_2024(self) -> bool {
pub fn at_least_rust_2024(self) -> bool {
self >= Edition::Edition2024
}
}

View File

@ -707,24 +707,28 @@ pub fn edition(self) -> edition::Edition {
self.ctxt().edition()
}
/// Is this edition 2015?
#[inline]
pub fn is_rust_2015(self) -> bool {
self.edition().is_rust_2015()
}
/// Are we allowed to use features from the Rust 2018 edition?
#[inline]
pub fn rust_2018(self) -> bool {
self.edition().rust_2018()
pub fn at_least_rust_2018(self) -> bool {
self.edition().at_least_rust_2018()
}
/// Are we allowed to use features from the Rust 2021 edition?
#[inline]
pub fn rust_2021(self) -> bool {
self.edition().rust_2021()
pub fn at_least_rust_2021(self) -> bool {
self.edition().at_least_rust_2021()
}
/// Are we allowed to use features from the Rust 2024 edition?
#[inline]
pub fn rust_2024(self) -> bool {
self.edition().rust_2024()
pub fn at_least_rust_2024(self) -> bool {
self.edition().at_least_rust_2024()
}
/// Returns the source callee.

View File

@ -90,6 +90,19 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext<
}
v
}));
items.extend(doc.inlined_foreigns.iter().flat_map(|((_, renamed), (res, local_import_id))| {
let Some(def_id) = res.opt_def_id() else { return Vec::new() };
let name = renamed.unwrap_or_else(|| cx.tcx.item_name(def_id));
let import = cx.tcx.hir().expect_item(*local_import_id);
match import.kind {
hir::ItemKind::Use(path, kind) => {
let hir::UsePath { segments, span, .. } = *path;
let path = hir::Path { segments, res: *res, span };
clean_use_statement_inner(import, name, &path, kind, cx, &mut Default::default())
}
_ => unreachable!(),
}
}));
items.extend(doc.items.values().flat_map(|(item, renamed, _)| {
// Now we actually lower the imports, skipping everything else.
if let hir::ItemKind::Use(path, hir::UseKind::Glob) = item.kind {
@ -2652,9 +2665,6 @@ fn clean_use_statement<'tcx>(
let mut items = Vec::new();
let hir::UsePath { segments, ref res, span } = *path;
for &res in res {
if let Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) = res {
continue;
}
let path = hir::Path { segments, res, span };
items.append(&mut clean_use_statement_inner(import, name, &path, kind, cx, inlined_names));
}
@ -2669,6 +2679,9 @@ fn clean_use_statement_inner<'tcx>(
cx: &mut DocContext<'tcx>,
inlined_names: &mut FxHashSet<(ItemType, Symbol)>,
) -> Vec<Item> {
if let Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) = path.res {
return Vec::new();
}
// We need this comparison because some imports (for std types for example)
// are "inserted" as well but directly by the compiler and they should not be
// taken into account.

View File

@ -35,6 +35,8 @@ pub(crate) struct Module<'hir> {
(LocalDefId, Option<Symbol>),
(&'hir hir::Item<'hir>, Option<Symbol>, Option<LocalDefId>),
>,
/// Same as for `items`.
pub(crate) inlined_foreigns: FxIndexMap<(DefId, Option<Symbol>), (Res, LocalDefId)>,
pub(crate) foreigns: Vec<(&'hir hir::ForeignItem<'hir>, Option<Symbol>)>,
}
@ -54,6 +56,7 @@ pub(crate) fn new(
import_id,
mods: Vec::new(),
items: FxIndexMap::default(),
inlined_foreigns: FxIndexMap::default(),
foreigns: Vec::new(),
}
}
@ -272,21 +275,30 @@ fn maybe_inline_local(
return false;
}
// For cross-crate impl inlining we need to know whether items are
// reachable in documentation -- a previously unreachable item can be
// made reachable by cross-crate inlining which we're checking here.
// (this is done here because we need to know this upfront).
if !ori_res_did.is_local() && !is_no_inline {
crate::visit_lib::lib_embargo_visit_item(self.cx, ori_res_did);
return false;
}
let is_hidden = !document_hidden && tcx.is_doc_hidden(ori_res_did);
let Some(res_did) = ori_res_did.as_local() else {
return false;
// For cross-crate impl inlining we need to know whether items are
// reachable in documentation -- a previously unreachable item can be
// made reachable by cross-crate inlining which we're checking here.
// (this is done here because we need to know this upfront).
crate::visit_lib::lib_embargo_visit_item(self.cx, ori_res_did);
if is_hidden {
return false;
}
// We store inlined foreign items otherwise, it'd mean that the `use` item would be kept
// around. It's not a problem unless this `use` imports both a local AND a foreign item.
// If a local item is inlined, its `use` is not supposed to still be around in `clean`,
// which would make appear the `use` in the generated documentation like the local item
// was not inlined even though it actually was.
self.modules
.last_mut()
.unwrap()
.inlined_foreigns
.insert((ori_res_did, renamed), (res, def_id));
return true;
};
let is_private = !self.cx.cache.effective_visibilities.is_directly_public(tcx, ori_res_did);
let is_hidden = !document_hidden && tcx.is_doc_hidden(ori_res_did);
let item = tcx.hir().get_by_def_id(res_did);
if !please_inline {
@ -314,7 +326,7 @@ fn maybe_inline_local(
return false;
}
let inlined = match tcx.hir().get_by_def_id(res_did) {
let inlined = match item {
// Bang macros are handled a bit on their because of how they are handled by the
// compiler. If they have `#[doc(hidden)]` and the re-export doesn't have
// `#[doc(inline)]`, then we don't inline it.
@ -346,7 +358,7 @@ fn maybe_inline_local(
};
self.view_item_stack.remove(&res_did);
if inlined {
self.cx.cache.inlined_items.insert(res_did.to_def_id());
self.cx.cache.inlined_items.insert(ori_res_did);
}
inlined
}
@ -483,7 +495,6 @@ fn visit_item_inner(
continue;
}
}
self.add_to_current_mod(item, renamed, import_id);
}
}

View File

@ -0,0 +1,24 @@
// compile-flags: -C opt-level=1
#![no_builtins]
#![crate_type = "lib"]
// CHECK: define
// CHECK-SAME: @__aeabi_memcpy
// CHECK-SAME: #0
#[no_mangle]
pub unsafe extern "C" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, size: usize) {
// CHECK: call
// CHECK-SAME: @memcpy(
memcpy(dest, src, size);
}
// CHECK: declare
// CHECK-SAME: @memcpy
// CHECK-SAME: #0
extern "C" {
pub fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
}
// CHECK: attributes #0
// CHECK-SAME: "no-builtins"

View File

@ -0,0 +1,9 @@
include ../tools.mk
# We want to check if `no-builtins` is also added to the function declarations in the used crate.
all:
$(RUSTC) no_builtins.rs --emit=link
$(RUSTC) main.rs --emit=llvm-ir
cat "$(TMPDIR)"/main.ll | "$(LLVM_FILECHECK)" filecheck.main.txt

View File

@ -0,0 +1,5 @@
CHECK: declare void @foo()
CHECK-SAME: #[[ATTR_3:[0-9]+]]
CHECK: attributes #[[ATTR_3]]
CHECK-SAME: no-builtins

View File

@ -0,0 +1,10 @@
extern crate no_builtins;
#[no_mangle]
fn call_foo() {
no_builtins::foo();
}
fn main() {
call_foo();
}

View File

@ -0,0 +1,5 @@
#![crate_type = "lib"]
#![no_builtins]
#[no_mangle]
pub fn foo() {}

View File

@ -0,0 +1,25 @@
// Regression test to ensure that both `AtomicU8` items are displayed but not the re-export.
#![crate_name = "foo"]
#![no_std]
// @has 'foo/index.html'
// @has - '//*[@class="item-name"]/a[@class="type"]' 'AtomicU8'
// @has - '//*[@class="item-name"]/a[@class="constant"]' 'AtomicU8'
// We also ensure we don't have another item displayed.
// @count - '//*[@id="main-content"]/*[@class="small-section-header"]' 2
// @has - '//*[@id="main-content"]/*[@class="small-section-header"]' 'Type Definitions'
// @has - '//*[@id="main-content"]/*[@class="small-section-header"]' 'Constants'
mod other {
pub type AtomicU8 = ();
}
mod thing {
pub use crate::other::AtomicU8;
#[allow(non_upper_case_globals)]
pub const AtomicU8: () = ();
}
pub use crate::thing::AtomicU8;

View File

@ -0,0 +1,21 @@
// Regression test to ensure that both `AtomicU8` items are displayed but not the re-export.
#![crate_name = "foo"]
#![no_std]
// @has 'foo/index.html'
// @has - '//*[@class="item-name"]/a[@class="struct"]' 'AtomicU8'
// @has - '//*[@class="item-name"]/a[@class="constant"]' 'AtomicU8'
// We also ensure we don't have another item displayed.
// @count - '//*[@id="main-content"]/*[@class="small-section-header"]' 2
// @has - '//*[@id="main-content"]/*[@class="small-section-header"]' 'Structs'
// @has - '//*[@id="main-content"]/*[@class="small-section-header"]' 'Constants'
mod thing {
pub use core::sync::atomic::AtomicU8;
#[allow(non_upper_case_globals)]
pub const AtomicU8: () = ();
}
pub use crate::thing::AtomicU8;

View File

@ -0,0 +1,8 @@
// issue: 112732
// `}` is typoed since it is interpreted as a fill character rather than a closing bracket
fn main() {
println!("Hello, world! {0:}<3", 2);
//~^ ERROR invalid format string: expected `'}'` but string was terminated
}

View File

@ -0,0 +1,12 @@
error: invalid format string: expected `'}'` but string was terminated
--> $DIR/closing-brace-as-fill.rs:6:35
|
LL | println!("Hello, world! {0:}<3", 2);
| - ^ expected `'}'` in format string
| |
| this is not interpreted as a formatting closing brace
|
= note: the character `'}'` is interpreted as a fill character because of the `:` that precedes it
error: aborting due to previous error

View File

@ -10,7 +10,7 @@ error: invalid format string: expected `'}'`, found `'a'`
LL | format!("{
| - because of this opening brace
LL | a");
| ^ expected `}` in format string
| ^ expected `'}'` in format string
|
= note: if you intended to print `{`, you can escape it using `{{`
@ -21,7 +21,7 @@ LL | format!("{ \
| - because of this opening brace
LL | \
LL | b");
| ^ expected `}` in format string
| ^ expected `'}'` in format string
|
= note: if you intended to print `{`, you can escape it using `{{`
@ -29,7 +29,7 @@ error: invalid format string: expected `'}'`, found `'\'`
--> $DIR/format-string-error-2.rs:11:18
|
LL | format!(r#"{ \
| - ^ expected `}` in format string
| - ^ expected `'}'` in format string
| |
| because of this opening brace
|
@ -39,7 +39,7 @@ error: invalid format string: expected `'}'`, found `'\'`
--> $DIR/format-string-error-2.rs:15:18
|
LL | format!(r#"{ \n
| - ^ expected `}` in format string
| - ^ expected `'}'` in format string
| |
| because of this opening brace
|
@ -52,7 +52,7 @@ LL | format!("{ \n
| - because of this opening brace
LL | \n
LL | e");
| ^ expected `}` in format string
| ^ expected `'}'` in format string
|
= note: if you intended to print `{`, you can escape it using `{{`
@ -62,7 +62,7 @@ error: invalid format string: expected `'}'`, found `'a'`
LL | {
| - because of this opening brace
LL | a");
| ^ expected `}` in format string
| ^ expected `'}'` in format string
|
= note: if you intended to print `{`, you can escape it using `{{`
@ -72,7 +72,7 @@ error: invalid format string: expected `'}'`, found `'a'`
LL | {
| - because of this opening brace
LL | a
| ^ expected `}` in format string
| ^ expected `'}'` in format string
|
= note: if you intended to print `{`, you can escape it using `{{`
@ -83,7 +83,7 @@ LL | { \
| - because of this opening brace
LL | \
LL | b");
| ^ expected `}` in format string
| ^ expected `'}'` in format string
|
= note: if you intended to print `{`, you can escape it using `{{`
@ -94,7 +94,7 @@ LL | { \
| - because of this opening brace
LL | \
LL | b \
| ^ expected `}` in format string
| ^ expected `'}'` in format string
|
= note: if you intended to print `{`, you can escape it using `{{`
@ -102,7 +102,7 @@ error: invalid format string: expected `'}'`, found `'\'`
--> $DIR/format-string-error-2.rs:45:8
|
LL | raw { \
| - ^ expected `}` in format string
| - ^ expected `'}'` in format string
| |
| because of this opening brace
|
@ -112,7 +112,7 @@ error: invalid format string: expected `'}'`, found `'\'`
--> $DIR/format-string-error-2.rs:50:8
|
LL | raw { \n
| - ^ expected `}` in format string
| - ^ expected `'}'` in format string
| |
| because of this opening brace
|
@ -125,7 +125,7 @@ LL | { \n
| - because of this opening brace
LL | \n
LL | e");
| ^ expected `}` in format string
| ^ expected `'}'` in format string
|
= note: if you intended to print `{`, you can escape it using `{{`
@ -135,7 +135,7 @@ error: invalid format string: expected `'}'`, found `'a'`
LL | {
| - because of this opening brace
LL | asdf}
| ^ expected `}` in format string
| ^ expected `'}'` in format string
|
= note: if you intended to print `{`, you can escape it using `{{`

View File

@ -62,7 +62,7 @@ error: invalid format string: expected `'}'`, found `'\'`
--> $DIR/format-string-error.rs:19:23
|
LL | let _ = format!("{\}");
| -^ expected `}` in format string
| -^ expected `'}'` in format string
| |
| because of this opening brace
|

View File

@ -26,7 +26,7 @@ error: invalid format string: expected `'}'`, found `'?'`
--> $DIR/format-string-wrong-order.rs:9:15
|
LL | format!("{??}", bar);
| -^ expected `}` in format string
| -^ expected `'}'` in format string
| |
| because of this opening brace
|
@ -36,7 +36,7 @@ error: invalid format string: expected `'}'`, found `'?'`
--> $DIR/format-string-wrong-order.rs:11:15
|
LL | format!("{?;bar}");
| -^ expected `}` in format string
| -^ expected `'}'` in format string
| |
| because of this opening brace
|

View File

@ -178,7 +178,7 @@ error: invalid format string: expected `'}'`, found `'t'`
LL | ninth number: {
| - because of this opening brace
LL | tenth number: {}",
| ^ expected `}` in format string
| ^ expected `'}'` in format string
|
= note: if you intended to print `{`, you can escape it using `{{`

View File

@ -0,0 +1,32 @@
// check-pass
#![feature(inline_const)]
// This used to be unsupported since the parser first tries to check if we have
// any nested items, and then checks for statements (and expressions). The heuristic
// that we were using to detect the beginning of a const item was incorrect, so
// this used to fail.
macro_rules! m {
($b:block) => {
fn foo() {
const $b
}
}
}
// This has worked since inline-consts were implemented, since the position that
// the const block is located at doesn't support nested items (e.g. because
// `let x = const X: u32 = 1;` is invalid), so there's no ambiguity parsing the
// inline const.
macro_rules! m2 {
($b:block) => {
fn foo2() {
let _ = const $b;
}
}
}
m!({});
m2!({});
fn main() {}

View File

@ -2,7 +2,7 @@ error: multiple declarations of external function `f` from library `foo.dll` hav
--> $DIR/multiple-declarations.rs:13:9
|
LL | fn f(x: i32);
| ^^^^^^^^^^^^^
| ^^^^^^^^^^^^
error: aborting due to previous error

View File

@ -2,7 +2,7 @@ error: ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture
--> $DIR/unsupported-abi.rs:6:5
|
LL | fn f(x: i32);
| ^^^^^^^^^^^^^
| ^^^^^^^^^^^^
error: aborting due to previous error

View File

@ -0,0 +1,39 @@
// revisions: old next
//[next] compile-flags: -Ztrait-solver=next
// run-pass
// A test for https://github.com/rust-lang/trait-system-refactor-initiative/issues/45.
trait Trait {
type Assoc: Into<u32>;
}
impl<T: Into<u32>> Trait for T {
type Assoc = T;
}
fn prefer_alias_bound_projection<T: Trait>(x: T::Assoc) {
// There are two possible types for `x`:
// - `u32` by using the "alias bound" of `<T as Trait>::Assoc`
// - `<T as Trait>::Assoc`, i.e. `u16`, by using `impl<T> From<T> for T`
//
// We infer the type of `x` to be `u32` here as it is highly likely
// that this is expected by the user.
let x = x.into();
assert_eq!(std::mem::size_of_val(&x), 4);
}
fn impl_trait() -> impl Into<u32> {
0u16
}
fn main() {
// There are two possible types for `x`:
// - `u32` by using the "alias bound" of `impl Into<u32>`
// - `impl Into<u32>`, i.e. `u16`, by using `impl<T> From<T> for T`
//
// We infer the type of `x` to be `u32` here as it is highly likely
// that this is expected by the user.
let x = impl_trait().into();
assert_eq!(std::mem::size_of_val(&x), 4);
prefer_alias_bound_projection::<u16>(1);
}