diff options
28 files changed, 621 insertions, 143 deletions
diff --git a/.travis.yml b/.travis.yml index 5c810b5064b..63fc4ddddcc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,7 @@ matrix: script: - ./mach build -d --verbose - ./mach test-unit + - ./mach test-compiletest - bash etc/ci/lockfile_changed.sh - bash etc/ci/manifest_changed.sh cache: diff --git a/components/canvas/lib.rs b/components/canvas/lib.rs index 5a0b1a9e596..7377e0385c7 100644 --- a/components/canvas/lib.rs +++ b/components/canvas/lib.rs @@ -2,7 +2,6 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#![feature(clone_from_slice)] #![feature(nonzero)] #![feature(plugin)] #![plugin(plugins)] diff --git a/components/compositing/lib.rs b/components/compositing/lib.rs index bf192bd044a..6434c3a8939 100644 --- a/components/compositing/lib.rs +++ b/components/compositing/lib.rs @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #![feature(box_syntax)] -#![feature(clone_from_slice)] #![feature(custom_derive)] #![feature(plugin)] #![feature(mpsc_select)] diff --git a/components/gfx/lib.rs b/components/gfx/lib.rs index c0868ade6f8..8bc6f8c8b4a 100644 --- a/components/gfx/lib.rs +++ b/components/gfx/lib.rs @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // For simd (currently x86_64/aarch64) -#![cfg_attr(any(target_arch = "x86_64", target_arch = "aarch64"), feature(convert))] #![cfg_attr(any(target_os = "linux", target_os = "android", target_os = "windows"), feature(heap_api))] #![feature(alloc)] diff --git a/components/layout/context.rs b/components/layout/context.rs index ca4ef0851dd..134a6f03b2b 100644 --- a/components/layout/context.rs +++ b/components/layout/context.rs @@ -50,6 +50,7 @@ pub fn heap_size_of_local_context() -> usize { }) } +// Keep this implementation in sync with the one in ports/geckolib/traversal.rs. fn create_or_get_local_context(shared_layout_context: &SharedLayoutContext) -> Rc<LocalLayoutContext> { LOCAL_CONTEXT_KEY.with(|r| { diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index 344250b75b1..f78d15b3b1b 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -6,6 +6,7 @@ dependencies = [ "bitflags 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "canvas 0.0.1", "canvas_traits 0.0.1", + "compiletest_helper 0.0.1", "compositing 0.0.1", "devtools 0.0.1", "devtools_traits 0.0.1", @@ -28,6 +29,7 @@ dependencies = [ "net_traits 0.0.1", "net_traits_tests 0.0.1", "offscreen_gl_context 0.1.0 (git+https://github.com/ecoal95/rust-offscreen-rendering-context)", + "plugin_compiletest 0.0.1", "plugin_tests 0.0.1", "profile 0.0.1", "profile_traits 0.0.1", @@ -241,6 +243,21 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] +name = "compiletest_helper" +version = "0.0.1" +dependencies = [ + "compiletest_rs 0.0.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "compiletest_rs" +version = "0.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "compositing" version = "0.0.1" dependencies = [ @@ -736,7 +753,7 @@ dependencies = [ "net_traits 0.0.1", "script_traits 0.0.1", "servo-egl 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "servo-glutin 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "servo-glutin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", "x11 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1403,6 +1420,14 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] +name = "plugin_compiletest" +version = "0.0.1" +dependencies = [ + "compiletest_helper 0.0.1", + "plugins 0.0.1", +] + +[[package]] name = "plugin_tests" version = "0.0.1" dependencies = [ @@ -1704,7 +1729,7 @@ dependencies = [ [[package]] name = "servo-glutin" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "android_glue 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1746,7 +1771,7 @@ dependencies = [ "servo-egl 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "servo-fontconfig 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "servo-freetype-sys 2.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "servo-glutin 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "servo-glutin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", "x11 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/components/servo/Cargo.toml b/components/servo/Cargo.toml index b12bbb2312d..1b0a92ff94e 100644 --- a/components/servo/Cargo.toml +++ b/components/servo/Cargo.toml @@ -41,6 +41,12 @@ path = "../../tests/unit/style" [dev-dependencies.util_tests] path = "../../tests/unit/util" +[dev-dependencies.compiletest_helper] +path = "../../tests/compiletest/helper" + +[dev-dependencies.plugin_compiletest] +path = "../../tests/compiletest/plugin" + [[test]] name = "reftest" path = "../../tests/reftest.rs" diff --git a/components/style/traversal.rs b/components/style/traversal.rs index d39da40f03e..781c99f619e 100644 --- a/components/style/traversal.rs +++ b/components/style/traversal.rs @@ -2,13 +2,11 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use context::{LocalStyleContext, SharedStyleContext, StyleContext}; +use context::{SharedStyleContext, StyleContext}; use dom::{OpaqueNode, TNode, TRestyleDamage, UnsafeNode}; use matching::{ApplicableDeclarations, ElementMatchMethods, MatchMethods, StyleSharingResult}; use selectors::bloom::BloomFilter; use std::cell::RefCell; -use std::mem; -use std::rc::Rc; use util::opts; use util::tid::tid; @@ -115,47 +113,6 @@ pub trait DomTraversalContext<'ln, N: TNode<'ln>> { fn process_postorder(&self, node: N); } -pub struct StandaloneStyleContext<'a> { - pub shared: &'a SharedStyleContext, - cached_local_style_context: Rc<LocalStyleContext>, -} - -impl<'a> StandaloneStyleContext<'a> { - pub fn new(_: &'a SharedStyleContext) -> Self { panic!("Not implemented") } -} - -impl<'a> StyleContext<'a> for StandaloneStyleContext<'a> { - fn shared_context(&self) -> &'a SharedStyleContext { - &self.shared - } - - fn local_context(&self) -> &LocalStyleContext { - &self.cached_local_style_context - } -} - -pub struct RecalcStyleOnly<'lc> { - context: StandaloneStyleContext<'lc>, - root: OpaqueNode, -} - -impl<'lc, 'ln, N: TNode<'ln>> DomTraversalContext<'ln, N> for RecalcStyleOnly<'lc> { - type SharedContext = SharedStyleContext; - #[allow(unsafe_code)] - fn new<'a>(shared: &'a Self::SharedContext, root: OpaqueNode) -> Self { - // See the comment in RecalcStyleAndConstructFlows::new for an explanation of why this is - // necessary. - let shared_lc: &'lc SharedStyleContext = unsafe { mem::transmute(shared) }; - RecalcStyleOnly { - context: StandaloneStyleContext::new(shared_lc), - root: root, - } - } - - fn process_preorder(&self, node: N) { recalc_style_at(&self.context, self.root, node); } - fn process_postorder(&self, _: N) {} -} - /// The recalc-style-for-node traversal, which styles each node and must run before /// layout computation. This computes the styles applied to each node. #[inline] diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock index 92ab7641c4e..796fcb6d639 100644 --- a/ports/cef/Cargo.lock +++ b/ports/cef/Cargo.lock @@ -4,7 +4,7 @@ version = "0.0.1" dependencies = [ "azure 0.4.0 (git+https://github.com/servo/rust-azure)", "cgl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "cocoa 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "cocoa 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "compositing 0.0.1", "core-foundation 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "core-graphics 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -216,17 +216,6 @@ dependencies = [ [[package]] name = "cocoa" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "core-graphics 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "objc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cocoa" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ @@ -695,7 +684,7 @@ dependencies = [ "net_traits 0.0.1", "script_traits 0.0.1", "servo-egl 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "servo-glutin 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "servo-glutin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", "x11 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1654,7 +1643,7 @@ dependencies = [ [[package]] name = "servo-glutin" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "android_glue 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1696,7 +1685,7 @@ dependencies = [ "servo-egl 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "servo-fontconfig 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "servo-freetype-sys 2.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "servo-glutin 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "servo-glutin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", "x11 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/ports/cef/Cargo.toml b/ports/cef/Cargo.toml index 029f51b1a9c..a47bfe10e21 100644 --- a/ports/cef/Cargo.toml +++ b/ports/cef/Cargo.toml @@ -66,7 +66,7 @@ features = ["plugins"] [target.x86_64-apple-darwin.dependencies] objc = "0.1" -cocoa = "0.1" +cocoa = "0.2" core-foundation = "0.2" core-graphics = "0.2" core-text = "1.0" diff --git a/ports/geckolib/bindings.rs b/ports/geckolib/bindings.rs index 96a5cb40705..845cca32e13 100644 --- a/ports/geckolib/bindings.rs +++ b/ports/geckolib/bindings.rs @@ -28,19 +28,22 @@ pub type intptr_t = int64_t; pub type uintptr_t = uint64_t; pub type intmax_t = ::libc::c_long; pub type uintmax_t = ::libc::c_ulong; -pub type Enum_NodeType = ::libc::c_uint; -pub const ELEMENT_NODE: ::libc::c_uint = 1; -pub const ATTRIBUTE_NODE: ::libc::c_uint = 2; -pub const TEXT_NODE: ::libc::c_uint = 3; -pub const CDATA_SECTION_NODE: ::libc::c_uint = 4; -pub const ENTITY_REFERENCE_NODE: ::libc::c_uint = 5; -pub const ENTITY_NODE: ::libc::c_uint = 6; -pub const PROCESSING_INSTRUCTION_NODE: ::libc::c_uint = 7; -pub const COMMENT_NODE: ::libc::c_uint = 8; -pub const DOCUMENT_NODE: ::libc::c_uint = 9; -pub const DOCUMENT_TYPE_NODE: ::libc::c_uint = 10; -pub const DOCUMENT_FRAGMENT_NODE: ::libc::c_uint = 11; -pub const NOTATION_NODE: ::libc::c_uint = 12; +#[derive(Clone, Copy)] +#[repr(u32)] +pub enum Enum_NodeType { + ELEMENT_NODE = 1, + ATTRIBUTE_NODE = 2, + TEXT_NODE = 3, + CDATA_SECTION_NODE = 4, + ENTITY_REFERENCE_NODE = 5, + ENTITY_NODE = 6, + PROCESSING_INSTRUCTION_NODE = 7, + COMMENT_NODE = 8, + DOCUMENT_NODE = 9, + DOCUMENT_TYPE_NODE = 10, + DOCUMENT_FRAGMENT_NODE = 11, + NOTATION_NODE = 12, +} pub enum Struct_RawGeckoNode { } pub type RawGeckoNode = Struct_RawGeckoNode; pub enum Struct_RawGeckoElement { } @@ -49,10 +52,15 @@ pub enum Struct_RawGeckoDocument { } pub type RawGeckoDocument = Struct_RawGeckoDocument; pub enum Struct_ServoNodeData { } pub type ServoNodeData = Struct_ServoNodeData; +pub enum Struct_ServoArcStyleSheet { } +pub type ServoArcStyleSheet = Struct_ServoArcStyleSheet; +pub enum Struct_ServoStyleSetData { } +pub type ServoStyleSetData = Struct_ServoStyleSetData; extern "C" { pub fn Gecko_ElementState(element: *mut RawGeckoElement) -> uint8_t; - pub fn Gecko_GetAttrAsUTF8(element: *mut RawGeckoElement, ns: *const uint8_t, - name: *const uint8_t, length: *mut uint32_t) + pub fn Gecko_GetAttrAsUTF8(element: *mut RawGeckoElement, + ns: *const uint8_t, name: *const uint8_t, + length: *mut uint32_t) -> *const ::libc::c_char; pub fn Gecko_ChildrenCount(node: *mut RawGeckoNode) -> uint32_t; pub fn Gecko_GetDocumentElement(document: *mut RawGeckoDocument) @@ -61,21 +69,50 @@ extern "C" { pub fn Gecko_GetLastChild(node: *mut RawGeckoNode) -> *mut RawGeckoNode; pub fn Gecko_GetPrevSibling(node: *mut RawGeckoNode) -> *mut RawGeckoNode; pub fn Gecko_GetNextSibling(node: *mut RawGeckoNode) -> *mut RawGeckoNode; + pub fn Gecko_GetParentElement(element: *mut RawGeckoElement) + -> *mut RawGeckoElement; + pub fn Gecko_GetFirstChildElement(element: *mut RawGeckoElement) + -> *mut RawGeckoElement; + pub fn Gecko_GetLastChildElement(element: *mut RawGeckoElement) + -> *mut RawGeckoElement; + pub fn Gecko_GetPrevSiblingElement(element: *mut RawGeckoElement) + -> *mut RawGeckoElement; + pub fn Gecko_GetNextSiblingElement(element: *mut RawGeckoElement) + -> *mut RawGeckoElement; pub fn Gecko_GetNodeData(node: *mut RawGeckoNode) -> *mut ServoNodeData; pub fn Gecko_GetParentNode(node: *mut RawGeckoNode) -> *mut RawGeckoNode; - pub fn Gecko_LocalName(element: *mut RawGeckoElement, length: *mut uint32_t) - -> *const uint16_t; + pub fn Gecko_LocalName(element: *mut RawGeckoElement, + length: *mut uint32_t) -> *const uint16_t; pub fn Gecko_IsHTMLElementInHTMLDocument(element: *mut RawGeckoElement) -> ::libc::c_int; pub fn Gecko_IsLink(element: *mut RawGeckoElement) -> ::libc::c_int; pub fn Gecko_IsTextNode(node: *mut RawGeckoNode) -> ::libc::c_int; - pub fn Gecko_IsVisitedLink(element: *mut RawGeckoElement) -> ::libc::c_int; - pub fn Gecko_IsUnvisitedLink(element: *mut RawGeckoElement) -> ::libc::c_int; - pub fn Gecko_Namespace(element: *mut RawGeckoElement, length: *mut uint32_t) - -> *const uint16_t; + pub fn Gecko_IsVisitedLink(element: *mut RawGeckoElement) + -> ::libc::c_int; + pub fn Gecko_IsUnvisitedLink(element: *mut RawGeckoElement) + -> ::libc::c_int; + pub fn Gecko_IsRootElement(element: *mut RawGeckoElement) + -> ::libc::c_int; + pub fn Gecko_Namespace(element: *mut RawGeckoElement, + length: *mut uint32_t) -> *const uint16_t; pub fn Gecko_NodeIsElement(node: *mut RawGeckoNode) -> ::libc::c_int; pub fn Gecko_SetNodeData(node: *mut RawGeckoNode, - data: *mut ServoNodeData) -> (); - pub fn Servo_RestyleDocument(aDoc: *mut RawGeckoDocument) -> (); - pub fn Servo_DropNodeData(data: *mut ServoNodeData) -> (); + data: *mut ServoNodeData); + pub fn Servo_RestyleDocument(doc: *mut RawGeckoDocument, + data: *mut ServoStyleSetData); + pub fn Servo_DropNodeData(data: *mut ServoNodeData); + pub fn Servo_StylesheetFromUTF8Bytes(bytes: *const uint8_t, + length: uint32_t) + -> *mut ServoArcStyleSheet; + pub fn Servo_AppendStyleSheet(sheet: *mut ServoArcStyleSheet, + data: *mut ServoStyleSetData); + pub fn Servo_PrependStyleSheet(sheet: *mut ServoArcStyleSheet, + data: *mut ServoStyleSetData); + pub fn Servo_RemoveStyleSheet(sheet: *mut ServoArcStyleSheet, + data: *mut ServoStyleSetData); + pub fn Servo_StyleSheetHasRules(sheet: *mut ServoArcStyleSheet) + -> ::libc::c_int; + pub fn Servo_DropStylesheet(sheet: *mut ServoArcStyleSheet); + pub fn Servo_InitStyleSetData() -> *mut ServoStyleSetData; + pub fn Servo_DropStyleSetData(data: *mut ServoStyleSetData); } diff --git a/ports/geckolib/data.rs b/ports/geckolib/data.rs new file mode 100644 index 00000000000..3e78c6c87ae --- /dev/null +++ b/ports/geckolib/data.rs @@ -0,0 +1,75 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use bindings::ServoStyleSetData; +use euclid::Size2D; +use euclid::size::TypedSize2D; +use num_cpus; +use std::cmp; +use std::collections::HashMap; +use std::sync::mpsc::{channel, Receiver, Sender}; +use std::sync::{Arc, RwLock}; +use style::animation::Animation; +use style::context::SharedStyleContext; +use style::dom::OpaqueNode; +use style::media_queries::{Device, MediaType}; +use style::parallel::WorkQueueData; +use style::selector_matching::Stylist; +use style::stylesheets::Stylesheet; +use util::geometry::ViewportPx; +use util::thread_state; +use util::workqueue::WorkQueue; + +pub struct PerDocumentStyleData { + + /// Rule processor. + pub stylist: Stylist, + + /// List of stylesheets, mirrored from Gecko. + pub stylesheets: Vec<Arc<Stylesheet>>, + + /// Whether the stylesheets list above has changed since the last restyle. + pub stylesheets_changed: bool, + + // FIXME(bholley): Hook these up to something. + pub new_animations_sender: Sender<Animation>, + pub new_animations_receiver: Receiver<Animation>, + pub running_animations: Arc<RwLock<HashMap<OpaqueNode, Vec<Animation>>>>, + pub expired_animations: Arc<RwLock<HashMap<OpaqueNode, Vec<Animation>>>>, + + // FIXME(bholley): This shouldn't be per-document. + pub work_queue: WorkQueue<SharedStyleContext, WorkQueueData>, +} + +impl PerDocumentStyleData { + pub fn new() -> PerDocumentStyleData { + // FIXME(bholley): Real window size. + let window_size: TypedSize2D<ViewportPx, f32> = Size2D::typed(800.0, 600.0); + let device = Device::new(MediaType::Screen, window_size); + + let (new_anims_sender, new_anims_receiver) = channel(); + let num_threads = cmp::max(num_cpus::get() * 3 / 4, 1); + + PerDocumentStyleData { + stylist: Stylist::new(device), + stylesheets: Vec::new(), + stylesheets_changed: true, + new_animations_sender: new_anims_sender, + new_animations_receiver: new_anims_receiver, + running_animations: Arc::new(RwLock::new(HashMap::new())), + expired_animations: Arc::new(RwLock::new(HashMap::new())), + work_queue: WorkQueue::new("StyleWorker", thread_state::LAYOUT, num_threads), + } + } + + pub fn borrow_mut_from_raw<'a>(data: *mut ServoStyleSetData) -> &'a mut Self { + unsafe { &mut *(data as *mut PerDocumentStyleData) } + } +} + +impl Drop for PerDocumentStyleData { + fn drop(&mut self) { + self.work_queue.shutdown(); + } +} diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index bb1d6bcae3e..9ad4c99577a 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -6,27 +6,22 @@ use app_units::Au; use bindings::RawGeckoDocument; -use bindings::ServoNodeData; +use bindings::{ServoArcStyleSheet, ServoNodeData, ServoStyleSetData, uint8_t, uint32_t}; +use data::PerDocumentStyleData; use euclid::Size2D; -use euclid::size::TypedSize2D; -use num_cpus; -use std::cmp; -use std::collections::HashMap; -use std::sync::mpsc::{channel, Sender}; -use std::sync::{Arc, Mutex, RwLock}; -use style::animation::Animation; +use std::mem::{forget, transmute}; +use std::slice; +use std::str::from_utf8_unchecked; +use std::sync::{Arc, Mutex}; use style::context::{ReflowGoal, SharedStyleContext, StylistWrapper}; use style::dom::{TDocument, TNode}; use style::error_reporting::StdoutErrorReporter; -use style::media_queries::{Device, MediaType}; -use style::parallel::{self, WorkQueueData}; -use style::selector_matching::Stylist; -use style::stylesheets::Stylesheet; -use style::traversal::RecalcStyleOnly; -use util::geometry::ViewportPx; +use style::parallel; +use style::stylesheets::{Origin, Stylesheet}; +use traversal::RecalcStyleOnly; +use url::Url; +use util::arc_ptr_eq; use util::resource_files::set_resources_path; -use util::thread_state; -use util::workqueue::WorkQueue; use wrapper::{GeckoDocument, GeckoNode, NonOpaqueStyleData}; /* @@ -38,50 +33,36 @@ use wrapper::{GeckoDocument, GeckoNode, NonOpaqueStyleData}; */ #[no_mangle] -pub extern "C" fn Servo_RestyleDocument(doc: *mut RawGeckoDocument) -> () { +pub extern "C" fn Servo_RestyleDocument(doc: *mut RawGeckoDocument, raw_data: *mut ServoStyleSetData) -> () { let document = unsafe { GeckoDocument::from_raw(doc) }; let node = match document.root_node() { Some(x) => x, None => return, }; + let data = unsafe { &mut *(raw_data as *mut PerDocumentStyleData) }; // FIXME(bholley): Don't hardcode resources path. We may want to use Gecko's UA stylesheets // anyway. set_resources_path(Some("/files/mozilla/stylo/servo/resources/".to_owned())); - // FIXME(bholley): Real window size. - let window_size: TypedSize2D<ViewportPx, f32> = Size2D::typed(800.0, 600.0); - let device = Device::new(MediaType::Screen, window_size); - - // FIXME(bholley): Real stylist and stylesheets. - let stylesheets: Vec<Arc<Stylesheet>> = Vec::new(); - let mut stylist = Box::new(Stylist::new(device)); - let _needs_dirtying = stylist.update(&stylesheets, false); - - // FIXME(bholley): Hook this up to something. - let new_animations_sender: Sender<Animation> = channel().0; + let _needs_dirtying = data.stylist.update(&data.stylesheets, data.stylesheets_changed); + data.stylesheets_changed = false; let shared_style_context = SharedStyleContext { viewport_size: Size2D::new(Au(0), Au(0)), screen_size_changed: false, generation: 0, goal: ReflowGoal::ForScriptQuery, - stylist: StylistWrapper(&*stylist), - new_animations_sender: Mutex::new(new_animations_sender), - running_animations: Arc::new(RwLock::new(HashMap::new())), - expired_animations: Arc::new(RwLock::new(HashMap::new())), + stylist: StylistWrapper(&data.stylist), + new_animations_sender: Mutex::new(data.new_animations_sender.clone()), + running_animations: data.running_animations.clone(), + expired_animations: data.expired_animations.clone(), error_reporter: Box::new(StdoutErrorReporter), }; - let num_threads = cmp::max(num_cpus::get() * 3 / 4, 1); - let mut parallel_traversal: WorkQueue<SharedStyleContext, WorkQueueData> = - WorkQueue::new("StyleWorker", thread_state::LAYOUT, num_threads); - if node.is_dirty() || node.has_dirty_descendants() { - parallel::traverse_dom::<GeckoNode, RecalcStyleOnly>(node, &shared_style_context, &mut parallel_traversal); + parallel::traverse_dom::<GeckoNode, RecalcStyleOnly>(node, &shared_style_context, &mut data.work_queue); } - - parallel_traversal.shutdown(); } #[no_mangle] @@ -90,3 +71,88 @@ pub extern "C" fn Servo_DropNodeData(data: *mut ServoNodeData) -> () { let _ = Box::<NonOpaqueStyleData>::from_raw(data as *mut NonOpaqueStyleData); } } + +#[no_mangle] +pub extern "C" fn Servo_StylesheetFromUTF8Bytes(bytes: *const uint8_t, + length: uint32_t) -> *mut ServoArcStyleSheet { + + let input = unsafe { from_utf8_unchecked(slice::from_raw_parts(bytes, length as usize)) }; + + // FIXME(heycam): Pass in the real base URL and sheet origin to use. + let url = Url::parse("about:none").unwrap(); + let sheet = Arc::new(Stylesheet::from_str(input, url, Origin::Author, Box::new(StdoutErrorReporter))); + unsafe { + transmute(sheet) + } +} + +fn with_arc_stylesheet<F, Output>(raw: *mut ServoArcStyleSheet, cb: F) -> Output + where F: FnOnce(&Arc<Stylesheet>) -> Output { + let owned = unsafe { consume_arc_stylesheet(raw) }; + let result = cb(&owned); + forget(owned); + result +} + +unsafe fn consume_arc_stylesheet(raw: *mut ServoArcStyleSheet) -> Arc<Stylesheet> { + transmute(raw) +} + +#[no_mangle] +pub extern "C" fn Servo_AppendStyleSheet(raw_sheet: *mut ServoArcStyleSheet, + raw_data: *mut ServoStyleSetData) { + let data = PerDocumentStyleData::borrow_mut_from_raw(raw_data); + with_arc_stylesheet(raw_sheet, |sheet| { + data.stylesheets.retain(|x| !arc_ptr_eq(x, sheet)); + data.stylesheets.push(sheet.clone()); + data.stylesheets_changed = true; + }); +} + +#[no_mangle] +pub extern "C" fn Servo_PrependStyleSheet(raw_sheet: *mut ServoArcStyleSheet, + raw_data: *mut ServoStyleSetData) { + let data = PerDocumentStyleData::borrow_mut_from_raw(raw_data); + with_arc_stylesheet(raw_sheet, |sheet| { + data.stylesheets.retain(|x| !arc_ptr_eq(x, sheet)); + data.stylesheets.insert(0, sheet.clone()); + data.stylesheets_changed = true; + }) +} + +#[no_mangle] +pub extern "C" fn Servo_RemoveStyleSheet(raw_sheet: *mut ServoArcStyleSheet, + raw_data: *mut ServoStyleSetData) { + let data = PerDocumentStyleData::borrow_mut_from_raw(raw_data); + with_arc_stylesheet(raw_sheet, |sheet| { + data.stylesheets.retain(|x| !arc_ptr_eq(x, sheet)); + data.stylesheets_changed = true; + }); +} + +#[no_mangle] +pub extern "C" fn Servo_StyleSheetHasRules(raw_sheet: *mut ServoArcStyleSheet) -> ::libc::c_int { + with_arc_stylesheet(raw_sheet, |sheet| if sheet.rules.is_empty() { 0 } else { 1 }) +} + + +#[no_mangle] +pub extern "C" fn Servo_DropStylesheet(sheet: *mut ServoArcStyleSheet) -> () { + unsafe { + let _ = consume_arc_stylesheet(sheet); + } +} + +#[no_mangle] +pub extern "C" fn Servo_InitStyleSetData() -> *mut ServoStyleSetData { + let data = Box::new(PerDocumentStyleData::new()); + Box::into_raw(data) as *mut ServoStyleSetData +} + + +#[no_mangle] +pub extern "C" fn Servo_DropStyleSetData(data: *mut ServoStyleSetData) -> () { + unsafe { + let _ = Box::<PerDocumentStyleData>::from_raw(data as *mut PerDocumentStyleData); + } +} diff --git a/ports/geckolib/lib.rs b/ports/geckolib/lib.rs index d1548b7fd94..e47d757b127 100644 --- a/ports/geckolib/lib.rs +++ b/ports/geckolib/lib.rs @@ -23,6 +23,8 @@ extern crate util; #[allow(dead_code, non_camel_case_types)] mod bindings; +mod data; #[allow(non_snake_case)] pub mod glue; +mod traversal; mod wrapper; diff --git a/ports/geckolib/traversal.rs b/ports/geckolib/traversal.rs new file mode 100644 index 00000000000..217035f5a52 --- /dev/null +++ b/ports/geckolib/traversal.rs @@ -0,0 +1,82 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use std::cell::RefCell; +use std::mem; +use std::rc::Rc; +use style::context::{LocalStyleContext, SharedStyleContext, StyleContext}; +use style::dom::{OpaqueNode, TNode}; +use style::matching::{ApplicableDeclarationsCache, StyleSharingCandidateCache}; +use style::traversal::{DomTraversalContext, recalc_style_at}; + +thread_local!(static LOCAL_CONTEXT_KEY: RefCell<Option<Rc<LocalStyleContext>>> = RefCell::new(None)); + +// Keep this implementation in sync with the one in components/layout/context.rs. +fn create_or_get_local_context(shared: &SharedStyleContext) + -> Rc<LocalStyleContext> { + LOCAL_CONTEXT_KEY.with(|r| { + let mut r = r.borrow_mut(); + if let Some(context) = r.clone() { + if shared.screen_size_changed { + context.applicable_declarations_cache.borrow_mut().evict_all(); + } + context + } else { + let context = Rc::new(LocalStyleContext { + applicable_declarations_cache: RefCell::new(ApplicableDeclarationsCache::new()), + style_sharing_candidate_cache: RefCell::new(StyleSharingCandidateCache::new()), + }); + *r = Some(context.clone()); + context + } + }) +} + +pub struct StandaloneStyleContext<'a> { + pub shared: &'a SharedStyleContext, + cached_local_context: Rc<LocalStyleContext>, +} + +impl<'a> StandaloneStyleContext<'a> { + pub fn new(shared: &'a SharedStyleContext) -> Self { + let local_context = create_or_get_local_context(shared); + StandaloneStyleContext { + shared: shared, + cached_local_context: local_context, + } + } +} + +impl<'a> StyleContext<'a> for StandaloneStyleContext<'a> { + fn shared_context(&self) -> &'a SharedStyleContext { + &self.shared + } + + fn local_context(&self) -> &LocalStyleContext { + &self.cached_local_context + } +} + +pub struct RecalcStyleOnly<'lc> { + context: StandaloneStyleContext<'lc>, + root: OpaqueNode, +} + +impl<'lc, 'ln, N: TNode<'ln>> DomTraversalContext<'ln, N> for RecalcStyleOnly<'lc> { + type SharedContext = SharedStyleContext; + #[allow(unsafe_code)] + fn new<'a>(shared: &'a Self::SharedContext, root: OpaqueNode) -> Self { + // See the comment in RecalcStyleAndConstructFlows::new for an explanation of why this is + // necessary. + let shared_lc: &'lc SharedStyleContext = unsafe { mem::transmute(shared) }; + RecalcStyleOnly { + context: StandaloneStyleContext::new(shared_lc), + root: root, + } + } + + fn process_preorder(&self, node: N) { recalc_style_at(&self.context, self.root, node); } + fn process_postorder(&self, _: N) {} +} + diff --git a/ports/geckolib/wrapper.rs b/ports/geckolib/wrapper.rs index 41b2b3ab1bc..03c436f7d28 100644 --- a/ports/geckolib/wrapper.rs +++ b/ports/geckolib/wrapper.rs @@ -6,9 +6,13 @@ use bindings::{Gecko_ChildrenCount}; use bindings::{Gecko_ElementState, Gecko_GetAttrAsUTF8, Gecko_GetDocumentElement}; -use bindings::{Gecko_GetFirstChild, Gecko_GetLastChild, Gecko_GetNodeData}; -use bindings::{Gecko_GetParentNode, Gecko_GetPrevSibling, Gecko_GetNextSibling}; -use bindings::{Gecko_IsHTMLElementInHTMLDocument, Gecko_IsLink, Gecko_IsTextNode}; +use bindings::{Gecko_GetFirstChild, Gecko_GetFirstChildElement}; +use bindings::{Gecko_GetLastChild, Gecko_GetLastChildElement}; +use bindings::{Gecko_GetNextSibling, Gecko_GetNextSiblingElement}; +use bindings::{Gecko_GetNodeData}; +use bindings::{Gecko_GetParentElement, Gecko_GetParentNode}; +use bindings::{Gecko_GetPrevSibling, Gecko_GetPrevSiblingElement}; +use bindings::{Gecko_IsHTMLElementInHTMLDocument, Gecko_IsLink, Gecko_IsRootElement, Gecko_IsTextNode}; use bindings::{Gecko_IsUnvisitedLink, Gecko_IsVisitedLink}; #[allow(unused_imports)] // Used in commented-out code. use bindings::{Gecko_LocalName, Gecko_Namespace, Gecko_NodeIsElement, Gecko_SetNodeData}; @@ -334,7 +338,7 @@ impl<'le> TElement<'le> for GeckoElement<'le> { fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, _hints: &mut V) where V: VecLike<DeclarationBlock<Vec<PropertyDeclaration>>> { - unimplemented!() + // FIXME(bholley) - Need to implement this. } #[inline] @@ -356,27 +360,39 @@ impl<'le> ::selectors::Element for GeckoElement<'le> { type Impl = ServoSelectorImpl; fn parent_element(&self) -> Option<Self> { - unimplemented!() + unsafe { + Gecko_GetParentElement(self.element).as_ref().map(|el| GeckoElement::from_ref(el)) + } } fn first_child_element(&self) -> Option<Self> { - unimplemented!() + unsafe { + Gecko_GetFirstChildElement(self.element).as_ref().map(|el| GeckoElement::from_ref(el)) + } } fn last_child_element(&self) -> Option<Self> { - unimplemented!() + unsafe { + Gecko_GetLastChildElement(self.element).as_ref().map(|el| GeckoElement::from_ref(el)) + } } fn prev_sibling_element(&self) -> Option<Self> { - unimplemented!() + unsafe { + Gecko_GetPrevSiblingElement(self.element).as_ref().map(|el| GeckoElement::from_ref(el)) + } } fn next_sibling_element(&self) -> Option<Self> { - unimplemented!() + unsafe { + Gecko_GetNextSiblingElement(self.element).as_ref().map(|el| GeckoElement::from_ref(el)) + } } fn is_root(&self) -> bool { - unimplemented!() + unsafe { + Gecko_IsRootElement(self.element) != 0 + } } fn is_empty(&self) -> bool { diff --git a/ports/gonk/Cargo.lock b/ports/gonk/Cargo.lock index d48c1c92f57..09893b87e30 100644 --- a/ports/gonk/Cargo.lock +++ b/ports/gonk/Cargo.lock @@ -1623,7 +1623,7 @@ dependencies = [ [[package]] name = "servo-glutin" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "android_glue 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1665,7 +1665,7 @@ dependencies = [ "servo-egl 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "servo-fontconfig 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "servo-freetype-sys 2.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "servo-glutin 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "servo-glutin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", "x11 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/python/servo/testing_commands.py b/python/servo/testing_commands.py index 142a59e766f..d9d26366d20 100644 --- a/python/servo/testing_commands.py +++ b/python/servo/testing_commands.py @@ -109,7 +109,10 @@ class MachCommands(CommandBase): "include_arg": "include"}), ("unit", {"kwargs": {}, "paths": [path.abspath(path.join("tests", "unit"))], - "include_arg": "test_name"}) + "include_arg": "test_name"}), + ("compiletest", {"kwargs": {"release": release}, + "paths": [path.abspath(path.join("tests", "compiletest"))], + "include_arg": "test_name"}) ]) suites_by_prefix = {path: k for k, v in suites.iteritems() if "paths" in v for path in v["paths"]} @@ -207,6 +210,65 @@ class MachCommands(CommandBase): if result != 0: return result + @Command('test-compiletest', + description='Run compiletests', + category='testing') + @CommandArgument('--package', '-p', default=None, help="Specific package to test") + @CommandArgument('test_name', nargs=argparse.REMAINDER, + help="Only run tests that match this pattern or file path") + @CommandArgument('--release', default=False, action="store_true", + help="Run with a release build of servo") + def test_compiletest(self, test_name=None, package=None, release=False): + if test_name is None: + test_name = [] + + self.ensure_bootstrapped() + + if package: + packages = {package} + else: + packages = set() + + test_patterns = [] + for test in test_name: + # add package if 'tests/compiletest/<package>' + match = re.search("tests/compiletest/(\\w+)/?$", test) + if match: + packages.add(match.group(1)) + # add package & test if '<package>/<test>', 'tests/compiletest/<package>/<test>.rs', or similar + elif re.search("\\w/\\w", test): + tokens = test.split("/") + packages.add(tokens[-2]) + test_prefix = tokens[-1] + if test_prefix.endswith(".rs"): + test_prefix = test_prefix[:-3] + test_prefix += "::" + test_patterns.append(test_prefix) + # add test as-is otherwise + else: + test_patterns.append(test) + + if not packages: + packages = set(os.listdir(path.join(self.context.topdir, "tests", "compiletest"))) + + packages.remove("helper") + + args = ["cargo", "test"] + for crate in packages: + args += ["-p", "%s_compiletest" % crate] + args += test_patterns + + env = self.build_env() + if release: + env["BUILD_MODE"] = "release" + args += ["--release"] + else: + env["BUILD_MODE"] = "debug" + + result = call(args, env=env, cwd=self.servo_crate()) + if result != 0: + return result + @Command('test-ref', description='Run the reference tests', category='testing') diff --git a/python/tidy.py b/python/tidy.py index c474c601954..2e160a5703a 100644 --- a/python/tidy.py +++ b/python/tidy.py @@ -168,7 +168,7 @@ def check_lock(file_name, contents): raise StopIteration # package names to be neglected (as named by cargo) - exceptions = ["cocoa"] + exceptions = [] import toml content = toml.loads(contents) diff --git a/tests/compiletest/helper/Cargo.toml b/tests/compiletest/helper/Cargo.toml new file mode 100644 index 00000000000..a5c3028d53c --- /dev/null +++ b/tests/compiletest/helper/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "compiletest_helper" +version = "0.0.1" +authors = ["The Servo Project Developers"] + +[lib] +name = "compiletest_helper" +path = "lib.rs" +doctest = false + +[dependencies.compiletest_rs] +compiletest_rs = "0.11" diff --git a/tests/compiletest/helper/lib.rs b/tests/compiletest/helper/lib.rs new file mode 100644 index 00000000000..2ec43d3f522 --- /dev/null +++ b/tests/compiletest/helper/lib.rs @@ -0,0 +1,29 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +extern crate compiletest_rs as compiletest; + +use std::env; +use std::path::PathBuf; + +pub fn run_mode(mode: &'static str) { + + let mut config = compiletest::default_config(); + let cfg_mode = mode.parse().ok().expect("Invalid mode"); + + config.mode = cfg_mode; + config.src_base = PathBuf::from(format!("{}", mode)); + + let mut base_path = env::current_dir().expect("Current directory is invalid"); + base_path.pop(); + base_path.pop(); + base_path.pop(); + + let mode = env::var("BUILD_MODE").expect("BUILD_MODE environment variable must be set"); + let debug_path = base_path.join(PathBuf::from(format!("target/{}", mode))); + let deps_path = base_path.join(PathBuf::from(format!("target/{}/deps", mode))); + + config.target_rustcflags = Some(format!("-L {} -L {}", debug_path.display(), deps_path.display())); + compiletest::run_tests(&config); +} diff --git a/tests/compiletest/plugin/Cargo.toml b/tests/compiletest/plugin/Cargo.toml new file mode 100644 index 00000000000..6ba2a22f198 --- /dev/null +++ b/tests/compiletest/plugin/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "plugin_compiletest" +version = "0.0.1" +authors = ["The Servo Project Developers"] + +[lib] +name = "plugin_compiletest" +path = "lib.rs" +doctest = false + +[dependencies.compiletest_helper] +path = "../helper" + +[dependencies.plugins] +path = "../../../components/plugins" diff --git a/tests/compiletest/plugin/compile-fail/ban.rs b/tests/compiletest/plugin/compile-fail/ban.rs new file mode 100644 index 00000000000..b789597d59d --- /dev/null +++ b/tests/compiletest/plugin/compile-fail/ban.rs @@ -0,0 +1,18 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#![feature(plugin)] +#![plugin(plugins)] + +extern crate js; + +use js::jsval::JSVal; +use std::cell::Cell; + +struct Foo { + bar: Cell<JSVal> + //~^ ERROR Banned type Cell<JSVal> detected. Use MutHeap<JSVal> instead, +} + +fn main() {} diff --git a/tests/compiletest/plugin/compile-fail/privatize.rs b/tests/compiletest/plugin/compile-fail/privatize.rs new file mode 100644 index 00000000000..a6f2ffdbe62 --- /dev/null +++ b/tests/compiletest/plugin/compile-fail/privatize.rs @@ -0,0 +1,16 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#![feature(plugin, custom_attribute)] +#![plugin(plugins)] +#![allow(dead_code)] + +#[privatize] +struct Foo { + pub v1: i32, + //~^ ERROR Field v1 is public where only private fields are allowed + v2: i32 +} + +fn main() {} diff --git a/tests/compiletest/plugin/compile-fail/str_to_string.rs b/tests/compiletest/plugin/compile-fail/str_to_string.rs new file mode 100644 index 00000000000..ee45ee39b96 --- /dev/null +++ b/tests/compiletest/plugin/compile-fail/str_to_string.rs @@ -0,0 +1,16 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#![feature(plugin)] +#![plugin(plugins)] + + +fn main() { + let x = "foo".to_string(); + //~^ ERROR str.to_owned() is more efficient than str.to_string() + + let x = &x[..]; + x.to_string(); + //~^ ERROR str.to_owned() is more efficient than str.to_string() +} diff --git a/tests/compiletest/plugin/compile-fail/transmute_type.rs b/tests/compiletest/plugin/compile-fail/transmute_type.rs new file mode 100644 index 00000000000..42bdd8c8c0f --- /dev/null +++ b/tests/compiletest/plugin/compile-fail/transmute_type.rs @@ -0,0 +1,19 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#![feature(plugin)] +#![plugin(plugins)] +#![allow(dead_code)] +#![deny(transmute_type_lint)] + +use std::mem::{self, transmute}; + + +fn main() { + let _: &[u8] = unsafe { transmute("Rust") }; + //~^ ERROR Transmute to &[u8] from &'static str detected + + let _: &[u8] = unsafe { mem::transmute("Rust") }; + //~^ ERROR Transmute to &[u8] from &'static str detected +} diff --git a/tests/compiletest/plugin/compile-fail/unrooted_must_root.rs b/tests/compiletest/plugin/compile-fail/unrooted_must_root.rs new file mode 100644 index 00000000000..f9b6d29dbee --- /dev/null +++ b/tests/compiletest/plugin/compile-fail/unrooted_must_root.rs @@ -0,0 +1,27 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#![feature(plugin)] +#![plugin(plugins)] +#![allow(dead_code)] + +#[must_root] +struct Foo { + v: i32 +} + +struct Bar { + f: Foo + //~^ ERROR Type must be rooted, use #[must_root] on the struct definition to propagate +} + +fn foo1(_: Foo) {} //~ ERROR Type must be rooted + + +fn foo2() -> Foo { //~ ERROR Type must be rooted + Foo { v: 10 } +} + + +fn main() {} diff --git a/tests/compiletest/plugin/lib.rs b/tests/compiletest/plugin/lib.rs new file mode 100644 index 00000000000..d3466c57b9b --- /dev/null +++ b/tests/compiletest/plugin/lib.rs @@ -0,0 +1,10 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +extern crate compiletest_helper; + +#[test] +fn compile_test() { + compiletest_helper::run_mode("compile-fail"); +} |