Skip to content

Commit

Permalink
Add ffi_const and ffi_pure extern fn attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
gnzlbg committed Feb 9, 2019
1 parent d173180 commit d8344ff
Show file tree
Hide file tree
Showing 18 changed files with 170 additions and 0 deletions.
23 changes: 23 additions & 0 deletions src/librustc/hir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2489,6 +2489,29 @@ bitflags! {
/// #[used], indicates that LLVM can't eliminate this function (but the
/// linker can!)
const USED = 1 << 9;
/// #[ffi_pure], indicates that a function has no effects except for
/// its return value, that its return value depends only on the
/// parameters and/or global variables, and that its return value does
/// not change between two consecutive calls (for example, because of
/// volatile access to the global variables).
///
/// Such a function can be subject to common sub-expression elimination
/// and loop optimization just as an arithmetic operator would be. Some
/// common examples of pure functions are `strlen` or `memcmp`.
const FFI_PURE = 1 << 10;
/// #[ffi_const], indicates that a function has no effects except for
/// its return value and that its return value depends only on the
/// value of the function parameters.
///
/// This attribute is stricter than `#[ffi_pure]`, since the function
/// return value is not allowed to depend on anything that is not the
/// value of the function parameters, like global memory, or other
/// values, like dereferencing a pointer function parameter to read
/// another value.
///
/// A `#[ffi_const]` function that returns void is a `nop` in the
/// abstract machine.
const FFI_CONST = 1 << 11;
}
}

Expand Down
6 changes: 6 additions & 0 deletions src/librustc_codegen_llvm/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,12 @@ pub fn from_fn_attrs(
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::COLD) {
Attribute::Cold.apply_llfn(Function, llfn);
}
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_PURE) {
Attribute::ReadOnly.apply_llfn(Function, llfn);
}
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_CONST) {
Attribute::ReadNone.apply_llfn(Function, llfn);
}
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
naked(llfn, true);
}
Expand Down
1 change: 1 addition & 0 deletions src/librustc_codegen_llvm/llvm/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ pub enum Attribute {
SanitizeMemory = 22,
NonLazyBind = 23,
OptimizeNone = 24,
ReadNone = 25,
}

/// LLVMIntPredicate
Expand Down
24 changes: 24 additions & 0 deletions src/librustc_typeck/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2270,6 +2270,30 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen
codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR;
} else if attr.check_name("unwind") {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::UNWIND;
} else if attr.check_name("ffi_pure") {
if tcx.is_foreign_item(id) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_PURE;
} else {
// `#[ffi_pure]` is only allowed `extern fn`s
struct_span_err!(
tcx.sess,
attr.span,
E0724,
"`#[ffi_pure]` may only be used on `extern fn`s"
).emit();
}
} else if attr.check_name("ffi_const") {
if tcx.is_foreign_item(id) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST;
} else {
// `#[ffi_const]` is only allowed `extern fn`s
struct_span_err!(
tcx.sess,
attr.span,
E0725,
"`#[ffi_const]` may only be used on `extern fn`s"
).emit();
}
} else if attr.check_name("rustc_allocator_nounwind") {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_ALLOCATOR_NOUNWIND;
} else if attr.check_name("naked") {
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_typeck/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4720,4 +4720,6 @@ register_diagnostics! {
E0698, // type inside generator must be known in this context
E0719, // duplicate values for associated type binding
E0722, // Malformed #[optimize] attribute
E0724, // `#[ffi_pure]` is only allowed `extern fn`s
E0725, // `#[ffi_const]` is only allowed `extern fn`s
}
16 changes: 16 additions & 0 deletions src/libsyntax/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,12 @@ declare_features! (
// The `repr(i128)` annotation for enums.
(active, repr128, "1.16.0", Some(35118), None),

// Allows the use of `#[ffi_pure]` on extern functions.
(active, ffi_pure, "1.34.0", Some(58329), None),

// Allows the use of `#[ffi_const]` on extern functions.
(active, ffi_const, "1.34.0", Some(58328), None),

// The `unadjusted` ABI; perma-unstable.
//
// rustc internal
Expand Down Expand Up @@ -1124,6 +1130,16 @@ pub const BUILTIN_ATTRIBUTES: &[(&str, AttributeType, AttributeTemplate, Attribu
"the `#[naked]` attribute \
is an experimental feature",
cfg_fn!(naked_functions))),
("ffi_pure", Whitelisted, template!(Word), Gated(Stability::Unstable,
"ffi_pure",
"the `#[ffi_pure]` attribute \
is an experimental feature",
cfg_fn!(ffi_pure))),
("ffi_const", Whitelisted, template!(Word), Gated(Stability::Unstable,
"ffi_const",
"the `#[ffi_const]` attribute \
is an experimental feature",
cfg_fn!(ffi_const))),
("target_feature", Whitelisted, template!(List: r#"enable = "name""#), Ungated),
("export_name", Whitelisted, template!(NameValueStr: "name"), Ungated),
("inline", Whitelisted, template!(Word, List: "always|never"), Ungated),
Expand Down
2 changes: 2 additions & 0 deletions src/rustllvm/RustWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) {
return Attribute::OptimizeForSize;
case ReadOnly:
return Attribute::ReadOnly;
case ReadNone:
return Attribute::ReadNone;
case SExt:
return Attribute::SExt;
case StructRet:
Expand Down
1 change: 1 addition & 0 deletions src/rustllvm/rustllvm.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ enum LLVMRustAttribute {
SanitizeMemory = 22,
NonLazyBind = 23,
OptimizeNone = 24,
ReadNone = 25,
};

typedef struct OpaqueRustString *RustStringRef;
Expand Down
16 changes: 16 additions & 0 deletions src/test/codegen/ffi-const.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// compile-flags: -C no-prepopulate-passes
#![crate_type = "lib"]
#![feature(ffi_const)]

// CHECK-LABEL: @bar()
#[no_mangle]
pub fn bar() { unsafe { foo() } }


extern {
// CHECK-LABEL: @foo() unnamed_addr #1
// CHECK: attributes #1 = { {{.*}}readnone{{.*}} }
#[no_mangle]
#[ffi_const]
pub fn foo();
}
13 changes: 13 additions & 0 deletions src/test/codegen/ffi-pure.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// compile-flags: -C no-prepopulate-passes
#![crate_type = "lib"]
#![feature(ffi_pure)]

// CHECK-LABEL: @bar()
#[no_mangle]
pub fn bar() { unsafe { foo() } }

extern {
// CHECK-LABEL: @foo() unnamed_addr #1
// CHECK: attributes #1 = { {{.*}}readonly{{.*}} }
#[ffi_pure] pub fn foo();
}
7 changes: 7 additions & 0 deletions src/test/ui/feature-gates/feature-gate-ffi_const.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// ignore-tidy-linelength
#![crate_type = "lib"]

extern {
#[ffi_const] //~ ERROR the `#[ffi_const]` attribute is an experimental feature (see issue #58314)
pub fn foo();
}
11 changes: 11 additions & 0 deletions src/test/ui/feature-gates/feature-gate-ffi_const.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error[E0658]: the `#[ffi_const]` attribute is an experimental feature (see issue #58314)
--> $DIR/feature-gate-ffi_const.rs:5:5
|
LL | #[ffi_const] //~ ERROR the `#[ffi_const]` attribute is an experimental feature (see issue #58314)
| ^^^^^^^^^^^^
|
= help: add #![feature(ffi_const)] to the crate attributes to enable

error: aborting due to previous error

For more information about this error, try `rustc --explain E0658`.
7 changes: 7 additions & 0 deletions src/test/ui/feature-gates/feature-gate-ffi_pure.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// ignore-tidy-linelength
#![crate_type = "lib"]

extern {
#[ffi_pure] //~ ERROR the `#[ffi_pure]` attribute is an experimental feature (see issue #58314)
pub fn foo();
}
11 changes: 11 additions & 0 deletions src/test/ui/feature-gates/feature-gate-ffi_pure.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error[E0658]: the `#[ffi_pure]` attribute is an experimental feature (see issue #58314)
--> $DIR/feature-gate-ffi_pure.rs:5:5
|
LL | #[ffi_pure] //~ ERROR the `#[ffi_pure]` attribute is an experimental feature (see issue #58314)
| ^^^^^^^^^^^
|
= help: add #![feature(ffi_pure)] to the crate attributes to enable

error: aborting due to previous error

For more information about this error, try `rustc --explain E0658`.
6 changes: 6 additions & 0 deletions src/test/ui/ffi_const.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// ignore-tidy-linelength
#![feature(ffi_const)]
#![crate_type = "lib"]

#[ffi_const] //~ ERROR `#[ffi_const]` may only be used on `extern fn`s [E0725]
pub fn foo() {}
9 changes: 9 additions & 0 deletions src/test/ui/ffi_const.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
error[E0725]: `#[ffi_const]` may only be used on `extern fn`s
--> $DIR/ffi_const.rs:5:1
|
LL | #[ffi_const] //~ ERROR `#[ffi_const]` may only be used on `extern fn`s [E0725]
| ^^^^^^^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0725`.
6 changes: 6 additions & 0 deletions src/test/ui/ffi_pure.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// ignore-tidy-linelength
#![feature(ffi_pure)]
#![crate_type = "lib"]

#[ffi_pure] //~ ERROR `#[ffi_pure]` may only be used on `extern fn`s [E0724]
pub fn foo() {}
9 changes: 9 additions & 0 deletions src/test/ui/ffi_pure.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
error[E0724]: `#[ffi_pure]` may only be used on `extern fn`s
--> $DIR/ffi_pure.rs:5:1
|
LL | #[ffi_pure] //~ ERROR `#[ffi_pure]` may only be used on `extern fn`s [E0724]
| ^^^^^^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0724`.

0 comments on commit d8344ff

Please sign in to comment.