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:
commit
39f42ad9e8
@ -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));
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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(
|
||||
|
@ -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 =
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)?;
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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())
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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()));
|
||||
|
@ -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);
|
||||
|
@ -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)]
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
24
tests/codegen/no_builtins-at-crate.rs
Normal file
24
tests/codegen/no_builtins-at-crate.rs
Normal 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"
|
9
tests/run-make/no-builtins-attribute/Makefile
Normal file
9
tests/run-make/no-builtins-attribute/Makefile
Normal 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
|
5
tests/run-make/no-builtins-attribute/filecheck.main.txt
Normal file
5
tests/run-make/no-builtins-attribute/filecheck.main.txt
Normal file
@ -0,0 +1,5 @@
|
||||
CHECK: declare void @foo()
|
||||
CHECK-SAME: #[[ATTR_3:[0-9]+]]
|
||||
|
||||
CHECK: attributes #[[ATTR_3]]
|
||||
CHECK-SAME: no-builtins
|
10
tests/run-make/no-builtins-attribute/main.rs
Normal file
10
tests/run-make/no-builtins-attribute/main.rs
Normal file
@ -0,0 +1,10 @@
|
||||
extern crate no_builtins;
|
||||
|
||||
#[no_mangle]
|
||||
fn call_foo() {
|
||||
no_builtins::foo();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
call_foo();
|
||||
}
|
5
tests/run-make/no-builtins-attribute/no_builtins.rs
Normal file
5
tests/run-make/no-builtins-attribute/no_builtins.rs
Normal file
@ -0,0 +1,5 @@
|
||||
#![crate_type = "lib"]
|
||||
#![no_builtins]
|
||||
|
||||
#[no_mangle]
|
||||
pub fn foo() {}
|
25
tests/rustdoc/issue-105735-overlapping-reexport-2.rs
Normal file
25
tests/rustdoc/issue-105735-overlapping-reexport-2.rs
Normal 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;
|
21
tests/rustdoc/issue-105735-overlapping-reexport.rs
Normal file
21
tests/rustdoc/issue-105735-overlapping-reexport.rs
Normal 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;
|
8
tests/ui/fmt/closing-brace-as-fill.rs
Normal file
8
tests/ui/fmt/closing-brace-as-fill.rs
Normal 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
|
||||
}
|
12
tests/ui/fmt/closing-brace-as-fill.stderr
Normal file
12
tests/ui/fmt/closing-brace-as-fill.stderr
Normal 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
|
||||
|
@ -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 `{{`
|
||||
|
||||
|
@ -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
|
||||
|
|
||||
|
@ -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
|
||||
|
|
||||
|
@ -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 `{{`
|
||||
|
||||
|
32
tests/ui/inline-const/interpolated.rs
Normal file
32
tests/ui/inline-const/interpolated.rs
Normal 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() {}
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
39
tests/ui/traits/new-solver/alias-bound-preference.rs
Normal file
39
tests/ui/traits/new-solver/alias-bound-preference.rs
Normal 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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user