Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions compiler/rustc_attr_parsing/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ attr_parsing_null_on_export = `export_name` may not contain null characters

attr_parsing_null_on_link_section = `link_section` may not contain null characters

attr_parsing_null_on_objc_class = `rustc_objc_class` may not contain null characters

attr_parsing_null_on_objc_selector = `rustc_objc_selector` may not contain null characters

attr_parsing_repr_ident =
meta item in `repr` must be an identifier

Expand Down
62 changes: 61 additions & 1 deletion compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ use rustc_hir::attrs::{CoverageAttrKind, OptimizeAttr, SanitizerSet, UsedBy};
use rustc_session::parse::feature_err;

use super::prelude::*;
use crate::session_diagnostics::{NakedFunctionIncompatibleAttribute, NullOnExport};
use crate::session_diagnostics::{
NakedFunctionIncompatibleAttribute, NullOnExport, NullOnObjcClass, NullOnObjcSelector,
};

pub(crate) struct OptimizeParser;

Expand Down Expand Up @@ -150,6 +152,64 @@ impl<S: Stage> SingleAttributeParser<S> for ExportNameParser {
}
}

pub(crate) struct ObjcClassParser;

impl<S: Stage> SingleAttributeParser<S> for ObjcClassParser {
const PATH: &[rustc_span::Symbol] = &[sym::rustc_objc_class];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::ForeignStatic)]);
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "ClassName");

fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
let Some(nv) = args.name_value() else {
cx.expected_name_value(cx.attr_span, None);
return None;
};
let Some(classname) = nv.value_as_str() else {
cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
return None;
};
if classname.as_str().contains('\0') {
// `#[rustc_objc_class = ...]` will be converted to a null-terminated string,
// so it may not contain any null characters.
cx.emit_err(NullOnObjcClass { span: cx.attr_span });
return None;
}
Some(AttributeKind::ObjcClass { classname, span: cx.attr_span })
}
}

pub(crate) struct ObjcSelectorParser;

impl<S: Stage> SingleAttributeParser<S> for ObjcSelectorParser {
const PATH: &[rustc_span::Symbol] = &[sym::rustc_objc_selector];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::ForeignStatic)]);
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "methodName");

fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
let Some(nv) = args.name_value() else {
cx.expected_name_value(cx.attr_span, None);
return None;
};
let Some(methname) = nv.value_as_str() else {
cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
return None;
};
if methname.as_str().contains('\0') {
// `#[rustc_objc_selector = ...]` will be converted to a null-terminated string,
// so it may not contain any null characters.
cx.emit_err(NullOnObjcSelector { span: cx.attr_span });
return None;
}
Some(AttributeKind::ObjcSelector { methname, span: cx.attr_span })
}
}

#[derive(Default)]
pub(crate) struct NakedParser {
span: Option<Span>,
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ use crate::attributes::allow_unstable::{
use crate::attributes::body::CoroutineParser;
use crate::attributes::codegen_attrs::{
ColdParser, CoverageParser, ExportNameParser, ForceTargetFeatureParser, NakedParser,
NoMangleParser, OptimizeParser, SanitizeParser, TargetFeatureParser, TrackCallerParser,
UsedParser,
NoMangleParser, ObjcClassParser, ObjcSelectorParser, OptimizeParser, SanitizeParser,
TargetFeatureParser, TrackCallerParser, UsedParser,
};
use crate::attributes::confusables::ConfusablesParser;
use crate::attributes::crate_level::CrateNameParser;
Expand Down Expand Up @@ -179,6 +179,8 @@ attribute_parsers!(
Single<LinkSectionParser>,
Single<LinkageParser>,
Single<MustUseParser>,
Single<ObjcClassParser>,
Single<ObjcSelectorParser>,
Single<OptimizeParser>,
Single<PathAttributeParser>,
Single<ProcMacroDeriveParser>,
Expand Down
14 changes: 14 additions & 0 deletions compiler/rustc_attr_parsing/src/session_diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,20 @@ pub(crate) struct NullOnLinkSection {
pub span: Span,
}

#[derive(Diagnostic)]
#[diag(attr_parsing_null_on_objc_class)]
pub(crate) struct NullOnObjcClass {
#[primary_span]
pub span: Span,
}

#[derive(Diagnostic)]
#[diag(attr_parsing_null_on_objc_selector)]
pub(crate) struct NullOnObjcSelector {
#[primary_span]
pub span: Span,
}

#[derive(Diagnostic)]
#[diag(attr_parsing_stability_outside_std, code = E0734)]
pub(crate) struct StabilityOutsideStd {
Expand Down
24 changes: 21 additions & 3 deletions compiler/rustc_codegen_llvm/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,18 +109,36 @@ pub(crate) fn compile_codegen_unit(
attributes::apply_to_llfn(entry, llvm::AttributePlace::Function, &attrs);
}

// Define Objective-C module info and module flags. Note, the module info will
// also be added to the `llvm.compiler.used` variable, created later.
//
// These are only necessary when we need the linker to do its Objective-C-specific
// magic. We could theoretically do it unconditionally, but at a slight cost to linker
// performance in the common case where it's unnecessary.
if !cx.objc_classrefs.borrow().is_empty() || !cx.objc_selrefs.borrow().is_empty() {
if cx.objc_abi_version() == 1 {
cx.define_objc_module_info();
}
cx.add_objc_module_flags();
}

// Finalize code coverage by injecting the coverage map. Note, the coverage map will
// also be added to the `llvm.compiler.used` variable, created next.
if cx.sess().instrument_coverage() {
cx.coverageinfo_finalize();
}

// Create the llvm.used and llvm.compiler.used variables.
// Create the llvm.used variable.
if !cx.used_statics.is_empty() {
cx.create_used_variable_impl(c"llvm.used", &cx.used_statics);
}
if !cx.compiler_used_statics.is_empty() {
cx.create_used_variable_impl(c"llvm.compiler.used", &cx.compiler_used_statics);

// Create the llvm.compiler.used variable.
{
let compiler_used_statics = cx.compiler_used_statics.borrow();
if !compiler_used_statics.is_empty() {
cx.create_used_variable_impl(c"llvm.compiler.used", &compiler_used_statics);
}
}

// Run replace-all-uses-with for statics that need it. This must
Expand Down
14 changes: 14 additions & 0 deletions compiler/rustc_codegen_llvm/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
bytes_in_context(self.llcx(), bytes)
}

pub(crate) fn null_terminate_const_bytes(&self, bytes: &[u8]) -> &'ll Value {
null_terminate_bytes_in_context(self.llcx(), bytes)
}

pub(crate) fn const_get_elt(&self, v: &'ll Value, idx: u64) -> &'ll Value {
unsafe {
let idx = c_uint::try_from(idx).expect("LLVMGetAggregateElement index overflow");
Expand Down Expand Up @@ -381,6 +385,16 @@ pub(crate) fn bytes_in_context<'ll>(llcx: &'ll llvm::Context, bytes: &[u8]) -> &
}
}

pub(crate) fn null_terminate_bytes_in_context<'ll>(
llcx: &'ll llvm::Context,
bytes: &[u8],
) -> &'ll Value {
unsafe {
let ptr = bytes.as_ptr() as *const c_char;
llvm::LLVMConstStringInContext2(llcx, ptr, bytes.len(), FALSE)
}
}

pub(crate) fn named_struct<'ll>(ty: &'ll Type, elts: &[&'ll Value]) -> &'ll Value {
let len = c_uint::try_from(elts.len()).expect("LLVMConstStructInContext elements len overflow");
unsafe { llvm::LLVMConstNamedStruct(ty, elts.as_ptr(), len) }
Expand Down
Loading
Loading