Skip to content
Closed
24 changes: 14 additions & 10 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1619,13 +1619,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
debug!(?hir_bounds);

let lifetime_mapping = if in_trait {
self.arena.alloc_from_iter(
collected_lifetime_mapping
.iter()
.map(|(lifetime, def_id)| (**lifetime, *def_id)),
Some(
&*self.arena.alloc_from_iter(
collected_lifetime_mapping
.iter()
.map(|(lifetime, def_id)| (**lifetime, *def_id)),
),
)
} else {
&mut []
None
};

let opaque_ty_item = hir::OpaqueTy {
Expand Down Expand Up @@ -2090,13 +2092,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params);

let lifetime_mapping = if in_trait {
self.arena.alloc_from_iter(
collected_lifetime_mapping
.iter()
.map(|(lifetime, def_id)| (**lifetime, *def_id)),
Some(
&*self.arena.alloc_from_iter(
collected_lifetime_mapping
.iter()
.map(|(lifetime, def_id)| (**lifetime, *def_id)),
),
)
} else {
&mut []
None
};

let opaque_ty_item = hir::OpaqueTy {
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_codegen_llvm/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down
10 changes: 9 additions & 1 deletion compiler/rustc_codegen_ssa/src/codegen_attrs.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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;
Expand Down
17 changes: 13 additions & 4 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2664,10 +2664,19 @@ pub struct OpaqueTy<'hir> {
pub generics: &'hir Generics<'hir>,
pub bounds: GenericBounds<'hir>,
pub origin: OpaqueTyOrigin,
// Opaques have duplicated lifetimes, this mapping connects the original lifetime with the copy
// so we can later generate bidirectional outlives predicates to enforce that these lifetimes
// stay in sync.
pub lifetime_mapping: &'hir [(Lifetime, LocalDefId)],
/// Return-position impl traits (and async futures) must "reify" any late-bound
/// lifetimes that are captured from the function signature they originate from.
///
/// This is done by generating a new early-bound lifetime parameter local to the
/// opaque which is substituted in the function signature with the late-bound
/// lifetime.
///
/// This mapping associated a captured lifetime (first parameter) with the new
/// early-bound lifetime that was generated for the opaque.
pub lifetime_mapping: Option<&'hir [(Lifetime, LocalDefId)]>,
/// Whether the opaque is a return-position impl trait (or async future)
/// originating from a trait method. This makes it so that the opaque is
/// lowered as an associated type.
pub in_trait: bool,
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/collect/predicates_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
let opaque_ty_id = tcx.hir().local_def_id_to_hir_id(opaque_def_id.expect_local());
let opaque_ty_node = tcx.hir().get(opaque_ty_id);
let Node::Item(&Item {
kind: ItemKind::OpaqueTy(OpaqueTy { lifetime_mapping, .. }),
kind: ItemKind::OpaqueTy(OpaqueTy { lifetime_mapping: Some(lifetime_mapping), .. }),
..
}) = opaque_ty_node
else {
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_lint/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -956,11 +956,11 @@ pub trait LintContext: Sized {
db.span_note(glob_reexport_span, format!("the name `{}` in the {} namespace is supposed to be publicly re-exported here", name, namespace));
db.span_note(private_item_span, "but the private item here shadows it".to_owned());
}
BuiltinLintDiagnostics::UnusedQualifications { path_span, unqualified_path } => {
BuiltinLintDiagnostics::UnusedQualifications { removal_span } => {
db.span_suggestion_verbose(
path_span,
"replace it with the unqualified path",
unqualified_path,
removal_span,
"remove the unnecessary path segments",
"",
Applicability::MachineApplicable
);
}
Expand Down
6 changes: 2 additions & 4 deletions compiler/rustc_lint_defs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -551,10 +551,8 @@ pub enum BuiltinLintDiagnostics {
private_item_span: Span,
},
UnusedQualifications {
/// The span of the unnecessarily-qualified path.
path_span: Span,
/// The replacement unqualified path.
unqualified_path: Ident,
/// The span of the unnecessarily-qualified path to remove.
removal_span: Span,
},
}

Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ bitflags! {
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;
}
}

Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3911,8 +3911,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
&& path[0].ident.name != kw::PathRoot
&& path[0].ident.name != kw::DollarCrate
{
let last_segment = *path.last().unwrap();
let unqualified_result = {
match self.resolve_path(&[*path.last().unwrap()], Some(ns), None) {
match self.resolve_path(&[last_segment], Some(ns), None) {
PathResult::NonModule(path_res) => path_res.expect_full_res(),
PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
module.res().unwrap()
Expand All @@ -3928,8 +3929,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
finalize.path_span,
"unnecessary qualification",
lint::BuiltinLintDiagnostics::UnusedQualifications {
path_span: finalize.path_span,
unqualified_path: path.last().unwrap().ident
removal_span: finalize.path_span.until(last_segment.ident.span),
}
)
}
Expand Down
4 changes: 2 additions & 2 deletions src/tools/compiletest/src/runtest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4149,8 +4149,8 @@ impl<'test> TestCx<'test> {
# Match paths that don't include spaces.
(?:\\[\pL\pN\.\-_']+)+\.\pL+
|
# If the path starts with a well-known root, then allow spaces.
\$(?:DIR|SRC_DIR|TEST_BUILD_DIR|BUILD_DIR|LIB_DIR)(?:\\[\pL\pN\.\-_' ]+)+
# If the path starts with a well-known root, then allow spaces and no file extension.
\$(?:DIR|SRC_DIR|TEST_BUILD_DIR|BUILD_DIR|LIB_DIR)(?:\\[\pL\pN\.\-_'\ ]+)+
)"#,
)
.unwrap()
Expand Down
8 changes: 4 additions & 4 deletions src/tools/compiletest/src/runtest/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ fn normalize_platform_differences() {
"$BUILD_DIR/../parser.rs"
);
assert_eq!(
TestCx::normalize_platform_differences(r"$DIR\bar.rs hello\nworld"),
r"$DIR/bar.rs hello\nworld"
TestCx::normalize_platform_differences(r"$DIR\bar.rs: hello\nworld"),
r"$DIR/bar.rs: hello\nworld"
);
assert_eq!(
TestCx::normalize_platform_differences(r"either bar\baz.rs or bar\baz\mod.rs"),
Expand All @@ -27,8 +27,8 @@ fn normalize_platform_differences() {
);
assert_eq!(TestCx::normalize_platform_differences(r"$DIR\foo.rs:12:11"), "$DIR/foo.rs:12:11",);
assert_eq!(
TestCx::normalize_platform_differences(r"$DIR\path with spaces 'n' quotes"),
"$DIR/path with spaces 'n' quotes",
TestCx::normalize_platform_differences(r"$DIR\path with\spaces 'n' quotes"),
"$DIR/path with/spaces 'n' quotes",
);
assert_eq!(
TestCx::normalize_platform_differences(r"$DIR\file_with\no_extension"),
Expand Down
23 changes: 23 additions & 0 deletions tests/codegen/no_builtins-at-crate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// compile-flags: -C opt-level=1

#![no_builtins]
#![crate_type = "lib"]

// CHECK: define void @__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 changes: 9 additions & 0 deletions tests/run-make/no-builtins-attribute/Makefile
Original file line number Diff line number Diff line change
@@ -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 changes: 5 additions & 0 deletions tests/run-make/no-builtins-attribute/filecheck.main.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
CHECK: declare void @foo()
CHECK-SAME: #[[ATTR_3:[0-9]+]]

CHECK: attributes #[[ATTR_3]]
CHECK-SAME: no-builtins
10 changes: 10 additions & 0 deletions tests/run-make/no-builtins-attribute/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
extern crate no_builtins;

#[no_mangle]
fn call_foo() {
no_builtins::foo();
}

fn main() {
call_foo();
}
5 changes: 5 additions & 0 deletions tests/run-make/no-builtins-attribute/no_builtins.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#![crate_type = "lib"]
#![no_builtins]

#[no_mangle]
pub fn foo() {}
21 changes: 21 additions & 0 deletions tests/ui/lint/lint-qualification.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// run-rustfix
#![deny(unused_qualifications)]
#![allow(deprecated)]

mod foo {
pub fn bar() {}
}

fn main() {
use foo::bar;
bar(); //~ ERROR: unnecessary qualification
bar();

let _ = || -> Result<(), ()> { try!(Ok(())); Ok(()) }; // issue #37345

macro_rules! m { () => {
$crate::foo::bar(); // issue #37357
::foo::bar(); // issue #38682
} }
m!();
}
1 change: 1 addition & 0 deletions tests/ui/lint/lint-qualification.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// run-rustfix
#![deny(unused_qualifications)]
#![allow(deprecated)]

Expand Down
11 changes: 6 additions & 5 deletions tests/ui/lint/lint-qualification.stderr
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
error: unnecessary qualification
--> $DIR/lint-qualification.rs:10:5
--> $DIR/lint-qualification.rs:11:5
|
LL | foo::bar();
| ^^^^^^^^
|
note: the lint level is defined here
--> $DIR/lint-qualification.rs:1:9
--> $DIR/lint-qualification.rs:2:9
|
LL | #![deny(unused_qualifications)]
| ^^^^^^^^^^^^^^^^^^^^^
help: replace it with the unqualified path
help: remove the unnecessary path segments
|
LL - foo::bar();
LL + bar();
|
LL | bar();
| ~~~

error: aborting due to previous error

Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// run-rustfix

#![deny(unused_qualifications)]
#![feature(unsized_fn_params)]

#[allow(unused_imports)]
use std::ops;
use std::ops::Index;

pub struct A;

impl Index<str> for A {
//~^ ERROR unnecessary qualification
type Output = ();
fn index(&self, _: str) -> &Self::Output {
&()
}
}

mod inner {
pub trait Trait<T> {}
}

// the import needs to be here for the lint to show up
#[allow(unused_imports)]
use inner::Trait;

impl Trait<u8> for () {}
//~^ ERROR unnecessary qualification

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// run-rustfix

#![deny(unused_qualifications)]
#![feature(unsized_fn_params)]

#[allow(unused_imports)]
use std::ops;
use std::ops::Index;

pub struct A;

impl ops::Index<str> for A {
//~^ ERROR unnecessary qualification
type Output = ();
fn index(&self, _: str) -> &Self::Output {
&()
}
}

mod inner {
pub trait Trait<T> {}
}

// the import needs to be here for the lint to show up
#[allow(unused_imports)]
use inner::Trait;

impl inner::Trait<u8> for () {}
//~^ ERROR unnecessary qualification

fn main() {}
Loading