Skip to content

Use compiletest_rs for testing various properties of the compiler #107

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 11 commits into from
Closed
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
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ members = [
"block2",
"block-sys",
"tests",
"compile-tests",
]
12 changes: 12 additions & 0 deletions compile-tests/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "compile-tests"
version = "0.1.0"
edition = "2018"
publish = false

repository = "https://github.com/madsmtm/objc2"
license = "MIT"

[dependencies]
compiletest_rs = "0.7"
cargo_metadata = "0.14"
19 changes: 19 additions & 0 deletions compile-tests/assembly/test_msg_send_zero_cost.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Test that msg_send! is inlined into an objc_msgSend
//
// assembly-output: emit-asm
// only-x86
// compile-flags: -Copt-level=2 -Clto=off

#![crate_type = "lib"]

use objc2::runtime::{Class, Object, Sel};
use objc2::MessageReceiver;

// CHECK-LABEL: handle:
// CHECK-NOT: j
// CHECK-NOT: call
// CHECK: jmp _objc_msgSend
#[no_mangle]
pub fn handle(obj: &Class, sel: Sel) -> *mut Object {
unsafe { MessageReceiver::send_message(&obj, sel, ()).unwrap() }
}
13 changes: 13 additions & 0 deletions compile-tests/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use std::env;

fn main() {
// For compile tests
println!(
"cargo:rustc-env=BUILD_PROFILE={}",
env::var("PROFILE").unwrap()
);
println!(
"cargo:rustc-env=BUILD_TARGET={}",
env::var("TARGET").unwrap()
);
}
84 changes: 84 additions & 0 deletions compile-tests/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
use cargo_metadata::camino::Utf8PathBuf;
use cargo_metadata::Message;
use std::env;
use std::io;
use std::path::Path;
use std::process::Command;
use std::process::Stdio;

use compiletest_rs::{common::Mode, run_tests, Config};

fn get_rlib<'a>(filenames: impl IntoIterator<Item = &'a Utf8PathBuf>) -> &'a Utf8PathBuf {
filenames
.into_iter()
.find(|name| name.extension() == Some("rlib"))
.expect("An rlib")
}

fn main() -> io::Result<()> {
let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR"));

// Build objc2
let result = Command::new("cargo")
.current_dir(&manifest_dir.parent().unwrap())
.arg("build")
.arg("-pobjc2")
.arg("--message-format=json-render-diagnostics")
.args(std::env::args().skip(1))
.stdout(Stdio::piped())
.output()?;

// Extract metadata from build
let artifacts: Vec<_> = cargo_metadata::Message::parse_stream(&*result.stdout)
.filter_map(|message| {
if let Message::CompilerArtifact(artifact) = message.unwrap() {
if artifact.target.kind == ["lib"] && !artifact.profile.test {
return Some(artifact);
}
}
None
})
.collect();
let dep_dir = get_rlib(&artifacts[0].filenames).parent().unwrap();
let flags = artifacts
.iter()
.map(|artifact| {
format!(
" --extern {name}={rlib}",
name = artifact.target.name,
rlib = get_rlib(&artifact.filenames),
)
})
.collect::<String>();

let mut config = Config::default();
config.target_rustcflags = Some(format!(
"-L dependency={dep}{flags}",
dep = dep_dir,
flags = flags,
));
config.llvm_filecheck = Some(
env::var("FILECHECK")
.unwrap_or("FileCheck".to_string())
.into(),
);
config.edition = Some("2018".into());
config.verbose = matches!(
std::env::var("CARGO_TERM_VERBOSE").as_deref(),
Ok("true" | "1")
) || std::env::args().any(|val| val == "--verbose" || val == "-v");

// Run UI tests
config.src_base = manifest_dir.join("ui");
config.mode = Mode::Ui;
run_tests(&config);
config.mode = Mode::CompileFail;
run_tests(&config);

// Run Codegen tests
config.src_base = manifest_dir.join("assembly");
config.mode = Mode::Assembly;
run_tests(&config);

Ok(())
}
11 changes: 11 additions & 0 deletions compile-tests/ui/msg_send_no_return_type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Test that forgetting to annotate the return type fails
// See https://github.com/SSheldon/rust-objc/issues/62
use objc2::{class, msg_send};

fn main() {
unsafe {
let cls = class!(NSObject);
msg_send![cls, new];
//~^ ERROR type annotations needed
}
}
11 changes: 11 additions & 0 deletions compile-tests/ui/msg_send_no_return_type.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error[E0282]: type annotations needed
--> $DIR/msg_send_no_return_type.rs:8:9
|
8 | msg_send![cls, new];
| ^^^^^^^^^^^^^^^^^^^ consider giving `result` a type
|
= note: this error originates in the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to previous error

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