Skip to content

Commit ee627eb

Browse files
committed
Auto merge of #155090 - JonathanBrouwer:rollup-6iOfyuw, r=JonathanBrouwer
Rollup of 2 pull requests Successful merges: - #153796 (Fix ICE when combining #[eii] with #[core::contracts::ensures]) - #155065 (error on invalid macho section specifier)
2 parents 25a54d4 + 537085f commit ee627eb

11 files changed

Lines changed: 233 additions & 5 deletions

File tree

compiler/rustc_attr_parsing/src/attributes/link_attrs.rs

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ use crate::attributes::cfg::parse_cfg_entry;
1414
use crate::session_diagnostics::{
1515
AsNeededCompatibility, BundleNeedsStatic, EmptyLinkName, ExportSymbolsNeedsStatic,
1616
ImportNameTypeRaw, ImportNameTypeX86, IncompatibleWasmLink, InvalidLinkModifier,
17-
LinkFrameworkApple, LinkOrdinalOutOfRange, LinkRequiresName, MultipleModifiers,
18-
NullOnLinkSection, RawDylibNoNul, RawDylibOnlyWindows, WholeArchiveNeedsStatic,
17+
InvalidMachoSection, InvalidMachoSectionReason, LinkFrameworkApple, LinkOrdinalOutOfRange,
18+
LinkRequiresName, MultipleModifiers, NullOnLinkSection, RawDylibNoNul, RawDylibOnlyWindows,
19+
WholeArchiveNeedsStatic,
1920
};
2021

2122
pub(crate) struct LinkNameParser;
@@ -465,6 +466,29 @@ impl LinkParser {
465466

466467
pub(crate) struct LinkSectionParser;
467468

469+
fn check_link_section_macho(name: Symbol) -> Result<(), InvalidMachoSectionReason> {
470+
let mut parts = name.as_str().split(',').map(|s| s.trim());
471+
472+
// The segment can be empty.
473+
let _segment = parts.next();
474+
475+
// But the section is required.
476+
let section = match parts.next() {
477+
None | Some("") => return Err(InvalidMachoSectionReason::MissingSection),
478+
Some(section) => section,
479+
};
480+
481+
if section.len() > 16 {
482+
return Err(InvalidMachoSectionReason::SectionTooLong { section: section.to_string() });
483+
}
484+
485+
// LLVM also checks the other components of the section specifier, but that logic is hard to
486+
// keep in sync. We skip it here for now, assuming that if you got that far you'll be able
487+
// to interpret the LLVM errors.
488+
489+
Ok(())
490+
}
491+
468492
impl<S: Stage> SingleAttributeParser<S> for LinkSectionParser {
469493
const PATH: &[Symbol] = &[sym::link_section];
470494
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
@@ -497,6 +521,18 @@ impl<S: Stage> SingleAttributeParser<S> for LinkSectionParser {
497521
return None;
498522
}
499523

524+
// We (currently) only validate macho section specifiers.
525+
match cx.sess.target.binary_format {
526+
BinaryFormat::MachO => match check_link_section_macho(name) {
527+
Ok(()) => {}
528+
Err(reason) => {
529+
cx.emit_err(InvalidMachoSection { name_span: nv.value_span, reason });
530+
return None;
531+
}
532+
},
533+
BinaryFormat::Coff | BinaryFormat::Elf | BinaryFormat::Wasm | BinaryFormat::Xcoff => {}
534+
}
535+
500536
Some(LinkSection { name, span: cx.attr_span })
501537
}
502538
}

compiler/rustc_attr_parsing/src/session_diagnostics.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1128,3 +1128,22 @@ pub(crate) struct UnstableAttrForAlreadyStableFeature {
11281128
#[label("the stability attribute annotates this item")]
11291129
pub item_span: Span,
11301130
}
1131+
1132+
#[derive(Diagnostic)]
1133+
#[diag("invalid macho section specifier")]
1134+
pub(crate) struct InvalidMachoSection {
1135+
#[primary_span]
1136+
#[label("not a valid macho section specifier")]
1137+
pub name_span: Span,
1138+
#[subdiagnostic]
1139+
pub reason: InvalidMachoSectionReason,
1140+
}
1141+
1142+
#[derive(Subdiagnostic)]
1143+
pub(crate) enum InvalidMachoSectionReason {
1144+
#[note("a macho section specifier requires a segment and a section, separated by a comma")]
1145+
#[help("an example of a valid macho section specifier is `__TEXT,__cstring`")]
1146+
MissingSection,
1147+
#[note("section name `{$section}` is longer than 16 bytes")]
1148+
SectionTooLong { section: String },
1149+
}

compiler/rustc_expand/src/expand.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -815,6 +815,27 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
815815
{
816816
rustc_parse::fake_token_stream_for_item(&self.cx.sess.psess, item_inner)
817817
}
818+
Annotatable::Item(item_inner) if item_inner.tokens.is_none() => {
819+
rustc_parse::fake_token_stream_for_item(&self.cx.sess.psess, item_inner)
820+
}
821+
// When a function has EII implementations attached (via `eii_impls`),
822+
// use fake tokens so the pretty-printer re-emits the EII attribute
823+
// (e.g. `#[hello]`) in the token stream. Without this, the EII
824+
// attribute is lost during the token roundtrip performed by
825+
// `AttrProcMacro` expanders like `contracts::requires/ensures`,
826+
// breaking the EII link on the resulting re-parsed item.
827+
Annotatable::Item(item_inner)
828+
if matches!(&item_inner.kind,
829+
ItemKind::Fn(f) if !f.eii_impls.is_empty()) =>
830+
{
831+
rustc_parse::fake_token_stream_for_item(&self.cx.sess.psess, item_inner)
832+
}
833+
Annotatable::ForeignItem(item_inner) if item_inner.tokens.is_none() => {
834+
rustc_parse::fake_token_stream_for_foreign_item(
835+
&self.cx.sess.psess,
836+
item_inner,
837+
)
838+
}
818839
_ => item.to_tokens(),
819840
};
820841
let attr_item = attr.get_normal_item();

compiler/rustc_hir/src/attrs/data_structures.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1090,8 +1090,8 @@ pub enum AttributeKind {
10901090

10911091
/// Represents [`#[link_section]`](https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute)
10921092
LinkSection {
1093-
name: Symbol,
10941093
span: Span,
1094+
name: Symbol,
10951095
},
10961096

10971097
/// Represents `#[linkage]`.

compiler/rustc_parse/src/lib.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,15 @@ pub fn fake_token_stream_for_item(psess: &ParseSess, item: &ast::Item) -> TokenS
257257
unwrap_or_emit_fatal(source_str_to_stream(psess, filename, source, Some(item.span)))
258258
}
259259

260+
pub fn fake_token_stream_for_foreign_item(
261+
psess: &ParseSess,
262+
item: &ast::ForeignItem,
263+
) -> TokenStream {
264+
let source = pprust::foreign_item_to_string(item);
265+
let filename = FileName::macro_expansion_source_code(&source);
266+
unwrap_or_emit_fatal(source_str_to_stream(psess, filename, source, Some(item.span)))
267+
}
268+
260269
pub fn fake_token_stream_for_crate(psess: &ParseSess, krate: &ast::Crate) -> TokenStream {
261270
let source = pprust::crate_to_string_for_macros(krate);
262271
let filename = FileName::macro_expansion_source_code(&source);

tests/codegen-llvm/naked-fn/naked-functions.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,13 +145,16 @@ pub extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize {
145145
}
146146

147147
// linux: .pushsection .text.some_different_name,\22ax\22, @progbits
148-
// macos: .pushsection .text.some_different_name,regular,pure_instructions
148+
// macos: .pushsection __TEXT,different,regular,pure_instructions
149149
// win_x86,win_i686: .pushsection .text.some_different_name,\22xr\22
150150
// thumb: .pushsection .text.some_different_name,\22ax\22, %progbits
151151
// CHECK-LABEL: test_link_section:
152152
#[no_mangle]
153153
#[unsafe(naked)]
154-
#[link_section = ".text.some_different_name"]
154+
// FIXME: configure this with `cfg(target_binary_format = "mach-o")`,
155+
// see https://github.com/rust-lang/rust/issues/152586.
156+
#[cfg_attr(not(target_vendor = "apple"), link_section = ".text.some_different_name")]
157+
#[cfg_attr(target_vendor = "apple", link_section = "__TEXT,different")]
155158
pub extern "C" fn test_link_section() {
156159
cfg_select! {
157160
all(target_arch = "arm", target_feature = "thumb-mode") => {
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//@ run-pass
2+
//@ ignore-backends: gcc
3+
//@ ignore-windows
4+
5+
#![feature(extern_item_impls)]
6+
#![feature(contracts)]
7+
#![allow(incomplete_features)]
8+
9+
#[eii(hello)]
10+
fn hello(x: u64);
11+
12+
#[hello]
13+
#[core::contracts::requires(x > 0)]
14+
fn hello_impl(x: u64) {
15+
println!("{x:?}")
16+
}
17+
18+
fn main() {
19+
hello(42);
20+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//@ compile-flags: --crate-type rlib
2+
3+
#![feature(extern_item_impls)]
4+
#![feature(contracts)]
5+
#![allow(incomplete_features)]
6+
7+
#[eii]
8+
#[core::contracts::ensures]
9+
//~^ ERROR contract annotations is only supported in functions with bodies
10+
//~| ERROR contract annotations can only be used on functions
11+
fn implementation();
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: contract annotations is only supported in functions with bodies
2+
--> $DIR/ice_contract_attr_on_eii_generated_item.rs:8:1
3+
|
4+
LL | #[core::contracts::ensures]
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
7+
error: contract annotations can only be used on functions
8+
--> $DIR/ice_contract_attr_on_eii_generated_item.rs:8:1
9+
|
10+
LL | #[core::contracts::ensures]
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
13+
error: aborting due to 2 previous errors
14+
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//@ add-minicore
2+
//@ compile-flags: --target aarch64-apple-darwin
3+
//@ needs-llvm-components: aarch64
4+
//@ ignore-backends: gcc
5+
#![feature(no_core, rustc_attrs, lang_items)]
6+
#![no_core]
7+
#![crate_type = "lib"]
8+
9+
extern crate minicore;
10+
use minicore::*;
11+
12+
#[unsafe(link_section = "foo")]
13+
//~^ ERROR invalid macho section specifier
14+
#[unsafe(no_mangle)]
15+
fn missing_section() {}
16+
17+
#[unsafe(link_section = "foo,")]
18+
//~^ ERROR invalid macho section specifier
19+
#[unsafe(no_mangle)]
20+
fn empty_section() {}
21+
22+
#[unsafe(link_section = "foo, ")]
23+
//~^ ERROR invalid macho section specifier
24+
#[unsafe(no_mangle)]
25+
fn whitespace_section() {}
26+
27+
#[unsafe(link_section = "foo,somelongwindedthing")]
28+
//~^ ERROR invalid macho section specifier
29+
#[unsafe(no_mangle)]
30+
fn section_too_long() {}
31+
32+
#[unsafe(link_section = "foo,bar")]
33+
#[unsafe(no_mangle)]
34+
fn segment_and_section() {}
35+
36+
#[unsafe(link_section = "foo,bar,")]
37+
#[unsafe(no_mangle)]
38+
fn segment_and_section_and_comma() {}
39+
40+
#[unsafe(link_section = ",foo")]
41+
#[unsafe(no_mangle)]
42+
fn missing_segment_is_fine() {}
43+
44+
#[unsafe(link_section = "__TEXT,__stubs,symbol_stubs,none,16")]
45+
#[unsafe(no_mangle)]
46+
fn stub_size_decimal() {}
47+
48+
#[unsafe(link_section = "__TEXT,__stubs,symbol_stubs,none,0x10")]
49+
#[unsafe(no_mangle)]
50+
fn stub_size_hex() {}
51+
52+
#[unsafe(link_section = "__TEXT,__stubs,symbol_stubs,none,020")]
53+
#[unsafe(no_mangle)]
54+
fn stub_size_oct() {}
55+
56+
#[unsafe(link_section = "__TEXT,__stubs,symbol_stubs,none,020,rest,is,ignored")]
57+
#[unsafe(no_mangle)]
58+
fn rest_is_ignored() {}

0 commit comments

Comments
 (0)