From 7f3491c39d008e320060099045ace5bebc46ce91 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 8 Mar 2016 21:44:19 +0000 Subject: [PATCH 01/23] Fix name resolution in lexical scopes --- src/librustc_resolve/lib.rs | 90 +++++++------------------ src/librustc_resolve/resolve_imports.rs | 3 +- 2 files changed, 26 insertions(+), 67 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index a205bfb98acfe..7415e9a9674f5 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1357,7 +1357,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { /// On success, returns the resolved module, and the closest *private* /// module found to the destination when resolving this path. fn resolve_module_path(&mut self, - module_: Module<'a>, module_path: &[Name], use_lexical_scope: UseLexicalScopeFlag, span: Span) @@ -1368,10 +1367,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { debug!("(resolving module path for import) processing `{}` rooted at `{}`", names_to_string(module_path), - module_to_string(&module_)); + module_to_string(self.current_module)); // Resolve the module prefix, if any. - let module_prefix_result = self.resolve_module_prefix(module_, module_path); + let module_prefix_result = self.resolve_module_prefix(module_path); let search_module; let start_index; @@ -1413,8 +1412,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // This is not a crate-relative path. We resolve the // first component of the path in the current lexical // scope and then proceed to resolve below that. - match self.resolve_item_in_lexical_scope(module_, - module_path[0], + match self.resolve_item_in_lexical_scope(module_path[0], TypeNS, true) { Failed(err) => return Failed(err), @@ -1448,61 +1446,30 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { /// Invariant: This must only be called during main resolution, not during /// import resolution. fn resolve_item_in_lexical_scope(&mut self, - module_: Module<'a>, name: Name, namespace: Namespace, record_used: bool) -> ResolveResult<&'a NameBinding<'a>> { - debug!("(resolving item in lexical scope) resolving `{}` in namespace {:?} in `{}`", - name, - namespace, - module_to_string(&module_)); - - // Proceed up the scope chain looking for parent modules. - let mut search_module = module_; - loop { - // Resolve the name in the parent module. - match self.resolve_name_in_module(search_module, name, namespace, true, record_used) { - Failed(Some((span, msg))) => { - resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); - } - Failed(None) => (), // Continue up the search chain. - Indeterminate => { - // We couldn't see through the higher scope because of an - // unresolved import higher up. Bail. - - debug!("(resolving item in lexical scope) indeterminate higher scope; bailing"); - return Indeterminate; - } - Success(binding) => { - // We found the module. - debug!("(resolving item in lexical scope) found name in module, done"); - return Success(binding); - } + // Check the local set of ribs. + for i in (0 .. self.get_ribs(namespace).len()).rev() { + if let Some(_) = self.get_ribs(namespace)[i].bindings.get(&name).cloned() { + return Failed(None); } - // Go to the next parent. - match search_module.parent_link { - NoParentLink => { - // No more parents. This module was unresolved. - debug!("(resolving item in lexical scope) unresolved module: no parent module"); - return Failed(None); - } - ModuleParentLink(parent_module_node, _) => { - if search_module.is_normal() { - // We stop the search here. - debug!("(resolving item in lexical scope) unresolved module: not \ - searching through module parents"); - return Failed(None); - } else { - search_module = parent_module_node; - } - } - BlockParentLink(parent_module_node, _) => { - search_module = parent_module_node; + if let ModuleRibKind(module) = self.get_ribs(namespace)[i].kind { + if let Success(binding) = self.resolve_name_in_module(module, + name, + namespace, + true, + record_used) { + return Success(binding); } + // We can only see through anonymous modules + if module.def.is_some() { return Failed(None); } } } + + Failed(None) } /// Returns the nearest normal module parent of the given module. @@ -1538,9 +1505,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { /// Resolves a "module prefix". A module prefix is one or both of (a) `self::`; /// (b) some chain of `super::`. /// grammar: (SELF MOD_SEP ) ? (SUPER MOD_SEP) * - fn resolve_module_prefix(&mut self, - module_: Module<'a>, - module_path: &[Name]) + fn resolve_module_prefix(&mut self, module_path: &[Name]) -> ResolveResult> { // Start at the current module if we see `self` or `super`, or at the // top of the crate otherwise. @@ -1549,6 +1514,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { "super" => 0, _ => return Success(NoPrefixFound), }; + let module_ = self.current_module; let mut containing_module = self.get_nearest_normal_module_parent_or_self(module_); // Now loop through all the `super`s we find. @@ -2594,8 +2560,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { name: Name, span: Span) -> BareIdentifierPatternResolution { - let module = self.current_module; - match self.resolve_item_in_lexical_scope(module, name, ValueNS, true) { + match self.resolve_item_in_lexical_scope(name, ValueNS, true) { Success(binding) => { debug!("(resolve bare identifier pattern) succeeded in finding {} at {:?}", name, @@ -2754,9 +2719,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } // Check the items. - let module = self.current_module; let name = identifier.unhygienic_name; - match self.resolve_item_in_lexical_scope(module, name, namespace, record_used) { + match self.resolve_item_in_lexical_scope(name, namespace, record_used) { Success(binding) => binding.def().map(LocalDef::from_def), Failed(Some((span, msg))) => { resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); @@ -2869,8 +2833,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { .collect::>(); let containing_module; - let current_module = self.current_module; - match self.resolve_module_path(current_module, &module_path, UseLexicalScope, span) { + match self.resolve_module_path(&module_path, UseLexicalScope, span) { Failed(err) => { let (span, msg) = match err { Some((span, msg)) => (span, msg), @@ -3024,7 +2987,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { span: Span, name_path: &[ast::Name]) -> Option> { - let root = this.current_module; let last_name = name_path.last().unwrap(); if name_path.len() == 1 { @@ -3034,7 +2996,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { .and_then(NameBinding::module) } } else { - this.resolve_module_path(root, &name_path, UseLexicalScope, span).success() + this.resolve_module_path(&name_path, UseLexicalScope, span).success() } } @@ -3274,10 +3236,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let name_path = path.segments.iter() .map(|seg| seg.identifier.name) .collect::>(); - let current_module = self.current_module; - match self.resolve_module_path(current_module, - &name_path[..], + match self.resolve_module_path(&name_path[..], UseLexicalScope, expr.span) { Success(_) => { diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index f1f47381e4c81..423604661ed56 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -427,8 +427,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { module_to_string(&module_)); self.resolver - .resolve_module_path(module_, - &import_directive.module_path, + .resolve_module_path(&import_directive.module_path, UseLexicalScopeFlag::DontUseLexicalScope, import_directive.span) .and_then(|containing_module| { From 210109cf7bc66fe9e4e9883cfe96e81381ba7d73 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 26 Feb 2016 05:39:33 +0000 Subject: [PATCH 02/23] Include the crate root in the ribs --- src/librustc_resolve/lib.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 7415e9a9674f5..11c2e0faea0d7 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1168,8 +1168,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { unresolved_imports: 0, current_module: graph_root, - value_ribs: Vec::new(), - type_ribs: Vec::new(), + value_ribs: vec![Rib::new(ModuleRibKind(graph_root))], + type_ribs: vec![Rib::new(ModuleRibKind(graph_root))], label_ribs: Vec::new(), current_trait_ref: None, @@ -2712,10 +2712,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } if check_ribs { - match self.resolve_identifier_in_local_ribs(identifier, namespace, record_used) { - Some(def) => return Some(def), - None => {} - } + return self.resolve_identifier_in_local_ribs(identifier, namespace, record_used); } // Check the items. From 87708b7b1f41e2373d128e5d11f72013812e26b0 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 8 Mar 2016 23:28:10 +0000 Subject: [PATCH 03/23] Refactor away check_ribs --- src/librustc_resolve/lib.rs | 58 ++++++++++++------------------------- 1 file changed, 18 insertions(+), 40 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 11c2e0faea0d7..eefef015636ae 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1874,7 +1874,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { trait_path: &Path, path_depth: usize) -> Result { - if let Some(path_res) = self.resolve_path(id, trait_path, path_depth, TypeNS, true) { + if let Some(path_res) = self.resolve_path(id, trait_path, path_depth, TypeNS) { if let Def::Trait(_) = path_res.base_def { debug!("(resolving trait) found trait def: {:?}", path_res); Ok(path_res) @@ -1932,7 +1932,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { &hir::WherePredicate::BoundPredicate(_) | &hir::WherePredicate::RegionPredicate(_) => {} &hir::WherePredicate::EqPredicate(ref eq_pred) => { - let path_res = self.resolve_path(eq_pred.id, &eq_pred.path, 0, TypeNS, true); + let path_res = self.resolve_path(eq_pred.id, &eq_pred.path, 0, TypeNS); if let Some(PathResolution { base_def: Def::TyParam(..), .. }) = path_res { self.record_def(eq_pred.id, path_res.unwrap()); } else { @@ -2198,8 +2198,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let resolution = match self.resolve_possibly_assoc_item(ty.id, maybe_qself.as_ref(), path, - TypeNS, - true) { + TypeNS) { // `::a::b::c` is resolved by typeck alone. TypecheckRequired => { // Resolve embedded types. @@ -2224,7 +2223,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { self.record_def(ty.id, err_path_resolution()); // Keep reporting some errors even if they're ignored above. - self.resolve_path(ty.id, path, 0, TypeNS, true); + self.resolve_path(ty.id, path, 0, TypeNS); let kind = if maybe_qself.is_some() { "associated type" @@ -2402,8 +2401,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let resolution = match self.resolve_possibly_assoc_item(pat_id, None, path, - ValueNS, - false) { + ValueNS) { // The below shouldn't happen because all // qualified paths should be in PatKind::QPath. TypecheckRequired => @@ -2475,8 +2473,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let resolution = match self.resolve_possibly_assoc_item(pat_id, Some(qself), path, - ValueNS, - false) { + ValueNS) { TypecheckRequired => { // All `::CONST` should end up here, and will // require use of the trait map to resolve @@ -2526,7 +2523,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } PatKind::Struct(ref path, _, _) => { - match self.resolve_path(pat_id, path, 0, TypeNS, false) { + match self.resolve_path(pat_id, path, 0, TypeNS) { Some(definition) => { self.record_def(pattern.id, definition); } @@ -2607,8 +2604,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { id: NodeId, maybe_qself: Option<&hir::QSelf>, path: &Path, - namespace: Namespace, - check_ribs: bool) + namespace: Namespace) -> AssocItemResolveResult { let max_assoc_types; @@ -2627,14 +2623,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } let mut resolution = self.with_no_errors(|this| { - this.resolve_path(id, path, 0, namespace, check_ribs) + this.resolve_path(id, path, 0, namespace) }); for depth in 1..max_assoc_types { if resolution.is_some() { break; } self.with_no_errors(|this| { - resolution = this.resolve_path(id, path, depth, TypeNS, true); + resolution = this.resolve_path(id, path, depth, TypeNS); }); } if let Some(Def::Mod(_)) = resolution.map(|r| r.base_def) { @@ -2644,16 +2640,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ResolveAttempt(resolution) } - /// If `check_ribs` is true, checks the local definitions first; i.e. - /// doesn't skip straight to the containing module. /// Skips `path_depth` trailing segments, which is also reflected in the /// returned value. See `middle::def::PathResolution` for more info. pub fn resolve_path(&mut self, id: NodeId, path: &Path, path_depth: usize, - namespace: Namespace, - check_ribs: bool) + namespace: Namespace) -> Option { let span = path.span; let segments = &path.segments[..path.segments.len() - path_depth]; @@ -2668,14 +2661,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // Try to find a path to an item in a module. let last_ident = segments.last().unwrap().identifier; if segments.len() <= 1 { - let unqualified_def = self.resolve_identifier(last_ident, namespace, check_ribs, true); + let unqualified_def = self.resolve_identifier(last_ident, namespace, true); return unqualified_def.and_then(|def| self.adjust_local_def(def, span)) .map(|def| { PathResolution::new(def, path_depth) }); } - let unqualified_def = self.resolve_identifier(last_ident, namespace, check_ribs, false); + let unqualified_def = self.resolve_identifier(last_ident, namespace, false); let def = self.resolve_module_relative_path(span, segments, namespace); match (def, unqualified_def) { (Some(d), Some(ref ud)) if d == ud.def => { @@ -2695,7 +2688,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn resolve_identifier(&mut self, identifier: hir::Ident, namespace: Namespace, - check_ribs: bool, record_used: bool) -> Option { if identifier.name == special_idents::invalid.name { @@ -2711,20 +2703,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - if check_ribs { - return self.resolve_identifier_in_local_ribs(identifier, namespace, record_used); - } - - // Check the items. - let name = identifier.unhygienic_name; - match self.resolve_item_in_lexical_scope(name, namespace, record_used) { - Success(binding) => binding.def().map(LocalDef::from_def), - Failed(Some((span, msg))) => { - resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); - None - } - _ => None, - } + self.resolve_identifier_in_local_ribs(identifier, namespace, record_used) } // Resolve a local definition, potentially adjusting for closures. @@ -3104,8 +3083,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let resolution = match self.resolve_possibly_assoc_item(expr.id, maybe_qself.as_ref(), path, - ValueNS, - true) { + ValueNS) { // `::a::b::c` is resolved by typeck alone. TypecheckRequired => { let method_name = path.segments.last().unwrap().identifier.name; @@ -3165,7 +3143,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // structs, which wouldn't result in this error.) let path_name = path_names_to_string(path, 0); let type_res = self.with_no_errors(|this| { - this.resolve_path(expr.id, path, 0, TypeNS, false) + this.resolve_path(expr.id, path, 0, TypeNS) }); self.record_def(expr.id, err_path_resolution()); @@ -3186,7 +3164,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } _ => { // Keep reporting some errors even if they're ignored above. - self.resolve_path(expr.id, path, 0, ValueNS, true); + self.resolve_path(expr.id, path, 0, ValueNS); let mut method_scope = false; self.value_ribs.iter().rev().all(|rib| { @@ -3260,7 +3238,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // Resolve the path to the structure it goes to. We don't // check to ensure that the path is actually a structure; that // is checked later during typeck. - match self.resolve_path(expr.id, path, 0, TypeNS, false) { + match self.resolve_path(expr.id, path, 0, TypeNS) { Some(definition) => self.record_def(expr.id, definition), None => { debug!("(resolving expression) didn't find struct def",); From e742da0c71fc65facfa04df045839a230f059d42 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 8 Mar 2016 23:33:48 +0000 Subject: [PATCH 04/23] Add regression test --- src/test/compile-fail/lexical-scopes.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/test/compile-fail/lexical-scopes.rs diff --git a/src/test/compile-fail/lexical-scopes.rs b/src/test/compile-fail/lexical-scopes.rs new file mode 100644 index 0000000000000..dbcd3f32f3b66 --- /dev/null +++ b/src/test/compile-fail/lexical-scopes.rs @@ -0,0 +1,23 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct T { i: i32 } +fn f() { + let t = T { i: 0 }; //~ ERROR `T` does not name a structure +} + +mod Foo { + pub fn f() {} +} +fn g() { + Foo::f(); //~ ERROR no associated item named `f` +} + +fn main() {} From 37efeae8866c3c4d9827d0ca271b8e27f731c3e1 Mon Sep 17 00:00:00 2001 From: Ruud van Asseldonk Date: Tue, 8 Mar 2016 21:41:18 +0100 Subject: [PATCH 05/23] Define AVX broadcast intrinsics This defines `_mm256_broadcast_ps` and `_mm256_broadcast_pd`. The `_ss` and `_sd` variants are not supported by LLVM. In Clang these intrinsics are implemented as inline functions in C++. Intel reference: https://software.intel.com/en-us/node/514144. Note: the argument type should really be "0hPc" (a pointer to a vector of half the width), but internally the LLVM intrinsic takes a pointer to a signed integer, and for any other type LLVM will complain. This means that a transmute is required to call these intrinsics. The AVX2 broadcast intrinsics `_mm256_broadcastss_ps` and `_mm256_broadcastsd_pd` are not available as LLVM intrinsics. In Clang they are implemented using the shufflevector builtin. --- src/etc/platform-intrinsics/x86/avx.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/etc/platform-intrinsics/x86/avx.json b/src/etc/platform-intrinsics/x86/avx.json index 2c1492c2954c8..981838536b2ff 100644 --- a/src/etc/platform-intrinsics/x86/avx.json +++ b/src/etc/platform-intrinsics/x86/avx.json @@ -8,6 +8,13 @@ "ret": "f(32-64)", "args": ["0", "0"] }, + { + "intrinsic": "256_broadcast_{0.data_type}", + "width": [256], + "llvm": "vbroadcastf128.{0.data_type}.256", + "ret": "f(32-64)", + "args": ["s8SPc"] + }, { "intrinsic": "256_dp_ps", "width": [256], From 51b5300b3fc83b445cd1e410be4b7d123f10472e Mon Sep 17 00:00:00 2001 From: Ruud van Asseldonk Date: Tue, 8 Mar 2016 22:36:54 +0100 Subject: [PATCH 06/23] Define AVX conversion intrinsics This defines the following intrinsics: * `_mm256_cvtepi32_pd` * `_mm256_cvtepi32_ps` * `_mm256_cvtpd_epi32` * `_mm256_cvtpd_ps` * `_mm256_cvtps_epi32` * `_mm256_cvtps_pd` * `_mm256_cvttpd_epi32` * `_mm256_cvttps_epi32` Intel reference: https://software.intel.com/en-us/node/514130. --- src/etc/platform-intrinsics/x86/avx.json | 56 ++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/etc/platform-intrinsics/x86/avx.json b/src/etc/platform-intrinsics/x86/avx.json index 981838536b2ff..08524fbd6dd8a 100644 --- a/src/etc/platform-intrinsics/x86/avx.json +++ b/src/etc/platform-intrinsics/x86/avx.json @@ -15,6 +15,62 @@ "ret": "f(32-64)", "args": ["s8SPc"] }, + { + "intrinsic": "256_cvtepi32_pd", + "width": [256], + "llvm": "cvtdq2.pd.256", + "ret": "f64", + "args": ["s32h"] + }, + { + "intrinsic": "256_cvtepi32_ps", + "width": [256], + "llvm": "cvtdq2.ps.256", + "ret": "f32", + "args": ["s32"] + }, + { + "intrinsic": "256_cvtpd_epi32", + "width": [256], + "llvm": "cvt.pd2dq.256", + "ret": "s32h", + "args": ["f64"] + }, + { + "intrinsic": "256_cvtpd_ps", + "width": [256], + "llvm": "cvt.pd2.ps.256", + "ret": "f32h", + "args": ["f64"] + }, + { + "intrinsic": "256_cvtps_epi32", + "width": [256], + "llvm": "cvt.ps2dq.256", + "ret": "s32", + "args": ["f32"] + }, + { + "intrinsic": "256_cvtps_pd", + "width": [256], + "llvm": "cvt.ps2.pd.256", + "ret": "f64", + "args": ["f32h"] + }, + { + "intrinsic": "256_cvttpd_epi32", + "width": [256], + "llvm": "cvtt.pd2dq.256", + "ret": "s32h", + "args": ["f64"] + }, + { + "intrinsic": "256_cvttps_epi32", + "width": [256], + "llvm": "cvtt.ps2dq.256", + "ret": "s32", + "args": ["f32"] + }, { "intrinsic": "256_dp_ps", "width": [256], From c306853edafb8b740c3e224ce4fa1842a6924dc5 Mon Sep 17 00:00:00 2001 From: Ruud van Asseldonk Date: Wed, 9 Mar 2016 01:16:31 +0100 Subject: [PATCH 07/23] Regenerate x86 platform intrinsics The exact command used was: $ cd src/etc/platform-intrinsics/x86 $ python2 ../generator.py --format compiler-defs -i info.json \ sse.json sse2.json sse3.json ssse3.json sse41.json sse42.json \ avx.json avx2.json fma.json \ > ../../../librustc_platform_intrinsics/x86.rs --- src/librustc_platform_intrinsics/x86.rs | 50 +++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/src/librustc_platform_intrinsics/x86.rs b/src/librustc_platform_intrinsics/x86.rs index 168ae79ab748f..d8aaf151267f6 100644 --- a/src/librustc_platform_intrinsics/x86.rs +++ b/src/librustc_platform_intrinsics/x86.rs @@ -498,6 +498,56 @@ pub fn find<'tcx>(_tcx: &TyCtxt<'tcx>, name: &str) -> Option { output: v(f(64), 4), definition: Named("llvm.x86.avx.addsub.pd.256") }, + "256_broadcast_ps" => Intrinsic { + inputs: vec![p(true, i(8), None)], + output: v(f(32), 8), + definition: Named("llvm.x86.avx.vbroadcastf128.ps.256") + }, + "256_broadcast_pd" => Intrinsic { + inputs: vec![p(true, i(8), None)], + output: v(f(64), 4), + definition: Named("llvm.x86.avx.vbroadcastf128.pd.256") + }, + "256_cvtepi32_pd" => Intrinsic { + inputs: vec![v(i(32), 4)], + output: v(f(64), 4), + definition: Named("llvm.x86.avx.cvtdq2.pd.256") + }, + "256_cvtepi32_ps" => Intrinsic { + inputs: vec![v(i(32), 8)], + output: v(f(32), 8), + definition: Named("llvm.x86.avx.cvtdq2.ps.256") + }, + "256_cvtpd_epi32" => Intrinsic { + inputs: vec![v(f(64), 4)], + output: v(i(32), 4), + definition: Named("llvm.x86.avx.cvt.pd2dq.256") + }, + "256_cvtpd_ps" => Intrinsic { + inputs: vec![v(f(64), 4)], + output: v(f(32), 4), + definition: Named("llvm.x86.avx.cvt.pd2.ps.256") + }, + "256_cvtps_epi32" => Intrinsic { + inputs: vec![v(f(32), 8)], + output: v(i(32), 8), + definition: Named("llvm.x86.avx.cvt.ps2dq.256") + }, + "256_cvtps_pd" => Intrinsic { + inputs: vec![v(f(32), 4)], + output: v(f(64), 4), + definition: Named("llvm.x86.avx.cvt.ps2.pd.256") + }, + "256_cvttpd_epi32" => Intrinsic { + inputs: vec![v(f(64), 4)], + output: v(i(32), 4), + definition: Named("llvm.x86.avx.cvtt.pd2dq.256") + }, + "256_cvttps_epi32" => Intrinsic { + inputs: vec![v(f(32), 8)], + output: v(i(32), 8), + definition: Named("llvm.x86.avx.cvtt.ps2dq.256") + }, "256_dp_ps" => Intrinsic { inputs: vec![v(f(32), 8), v(f(32), 8), i_(32, 8)], output: v(f(32), 8), From ae7fca1e1f5d74bf88ffacaf339b28d8c73f8c4f Mon Sep 17 00:00:00 2001 From: mitaa Date: Wed, 9 Mar 2016 02:05:39 +0100 Subject: [PATCH 08/23] Check for `doc(inline)` instead of `.*(inline)` --- src/librustdoc/visit_ast.rs | 4 +-- .../rustdoc/inline_local/please_inline.rs | 29 +++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 src/test/rustdoc/inline_local/please_inline.rs diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index bc6b4f83984b0..7a3adc157c261 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -276,10 +276,10 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let node = if item.vis == hir::Public { let please_inline = item.attrs.iter().any(|item| { match item.meta_item_list() { - Some(list) => { + Some(list) if &item.name()[..] == "doc" => { list.iter().any(|i| &i.name()[..] == "inline") } - None => false, + _ => false, } }); match self.visit_view_path(node, om, item.id, please_inline) { diff --git a/src/test/rustdoc/inline_local/please_inline.rs b/src/test/rustdoc/inline_local/please_inline.rs new file mode 100644 index 0000000000000..d237ab8dab01a --- /dev/null +++ b/src/test/rustdoc/inline_local/please_inline.rs @@ -0,0 +1,29 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub mod foo { + pub struct Foo; +} + +// @has please_inline/a/index.html +pub mod a { + // @!has - 'pub use foo::' + // @has please_inline/a/struct.Foo.html + #[doc(inline)] + pub use foo::Foo; +} + +// @has please_inline/b/index.html +pub mod b { + // @has - 'pub use foo::' + // @!has please_inline/b/struct.Foo.html + #[feature(inline)] + pub use foo::Foo; +} From 59279b5abbb8c7780f44c82bb8a8bdb0fbacbecd Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 9 Mar 2016 16:53:19 -0500 Subject: [PATCH 09/23] Do not report errors from regionck if other errors were already reported during the lifetime of this inferencer. Fixes #30580. --- src/librustc/middle/infer/mod.rs | 15 +++++++++++++-- src/test/compile-fail/issue-30580.rs | 24 ++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 src/test/compile-fail/issue-30580.rs diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index b9a5b32b71d82..dc0076e59f8c4 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -1107,11 +1107,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .map(|method| resolve_ty(method.ty))) } + pub fn errors_since_creation(&self) -> bool { + self.tcx.sess.err_count() - self.err_count_on_creation != 0 + } + pub fn node_type(&self, id: ast::NodeId) -> Ty<'tcx> { match self.tables.borrow().node_types.get(&id) { Some(&t) => t, // FIXME - None if self.tcx.sess.err_count() - self.err_count_on_creation != 0 => + None if self.errors_since_creation() => self.tcx.types.err, None => { self.tcx.sess.bug( @@ -1134,7 +1138,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { free_regions: &FreeRegionMap, subject_node_id: ast::NodeId) { let errors = self.region_vars.resolve_regions(free_regions, subject_node_id); - self.report_region_errors(&errors); // see error_reporting.rs + if !self.errors_since_creation() { + // As a heuristic, just skip reporting region errors + // altogether if other errors have been reported while + // this infcx was in use. This is totally hokey but + // otherwise we have a hard time separating legit region + // errors from silly ones. + self.report_region_errors(&errors); // see error_reporting.rs + } } pub fn ty_to_string(&self, t: Ty<'tcx>) -> String { diff --git a/src/test/compile-fail/issue-30580.rs b/src/test/compile-fail/issue-30580.rs new file mode 100644 index 0000000000000..908a2d47401e5 --- /dev/null +++ b/src/test/compile-fail/issue-30580.rs @@ -0,0 +1,24 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub struct Foo { a: u32 } +pub struct Pass<'a, 'tcx: 'a>(&'a mut &'a (), &'a &'tcx ()); + +impl<'a, 'tcx> Pass<'a, 'tcx> +{ + pub fn tcx(&self) -> &'a &'tcx () { self.1 } + fn lol(&mut self, b: &Foo) + { + b.c; //~ ERROR no field with that name was found + self.tcx(); + } +} + +fn main() {} From a20e6bb1627f8669b334e673740f78e435cd0321 Mon Sep 17 00:00:00 2001 From: mitaa Date: Thu, 10 Mar 2016 03:29:46 +0100 Subject: [PATCH 10/23] Consider `doc(hidden)` for crate-local inlining --- src/librustdoc/visit_ast.rs | 42 +++++++++++++++++--- src/test/rustdoc/inline_local/issue-28537.rs | 27 +++++++++++++ 2 files changed, 63 insertions(+), 6 deletions(-) create mode 100644 src/test/rustdoc/inline_local/issue-28537.rs diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 7a3adc157c261..4c03abac9e867 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -26,6 +26,7 @@ use rustc::middle::stability; use rustc_front::hir; use core; +use clean::{Clean, Attributes}; use doctree::*; // looks to me like the first two of these are actually @@ -182,7 +183,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { please_inline: bool) -> Option { match path { hir::ViewPathSimple(dst, base) => { - if self.resolve_id(id, Some(dst), false, om, please_inline) { + if self.maybe_inline_local(id, Some(dst), false, om, please_inline) { None } else { Some(hir::ViewPathSimple(dst, base)) @@ -190,7 +191,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } hir::ViewPathList(p, paths) => { let mine = paths.into_iter().filter(|path| { - !self.resolve_id(path.node.id(), None, false, om, + !self.maybe_inline_local(path.node.id(), None, false, om, please_inline) }).collect::>(); @@ -201,9 +202,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } } - // these are feature gated anyway hir::ViewPathGlob(base) => { - if self.resolve_id(id, None, true, om, please_inline) { + if self.maybe_inline_local(id, None, true, om, please_inline) { None } else { Some(hir::ViewPathGlob(base)) @@ -213,8 +213,32 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } - fn resolve_id(&mut self, id: ast::NodeId, renamed: Option, + /// Tries to resolve the target of a `pub use` statement and inlines the + /// target if it is defined locally and would not be documented otherwise, + /// or when it is specifically requested with `please_inline`. + /// (the latter is the case when the import is marked `doc(inline)`) + /// + /// Cross-crate inlining occurs later on during crate cleaning + /// and follows different rules. + /// + /// Returns true if the target has been inlined. + fn maybe_inline_local(&mut self, id: ast::NodeId, renamed: Option, glob: bool, om: &mut Module, please_inline: bool) -> bool { + + fn inherits_doc_hidden(cx: &core::DocContext, mut node: ast::NodeId) -> bool { + while let Some(id) = cx.map.get_enclosing_scope(node) { + node = id; + let attrs = cx.map.attrs(node).clean(cx); + if attrs.list_def("doc").has_word("hidden") { + return true; + } + if node == ast::CRATE_NODE_ID { + break; + } + } + false + } + let tcx = match self.cx.tcx_opt() { Some(tcx) => tcx, None => return false @@ -226,9 +250,15 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let analysis = match self.analysis { Some(analysis) => analysis, None => return false }; - if !please_inline && analysis.access_levels.is_public(def) { + + let is_private = !analysis.access_levels.is_public(def); + let is_hidden = inherits_doc_hidden(self.cx, def_node_id); + + // Only inline if requested or if the item would otherwise be stripped + if !please_inline && !is_private && !is_hidden { return false } + if !self.view_item_stack.insert(def_node_id) { return false } let ret = match tcx.map.get(def_node_id) { diff --git a/src/test/rustdoc/inline_local/issue-28537.rs b/src/test/rustdoc/inline_local/issue-28537.rs new file mode 100644 index 0000000000000..b38e104b7b4ee --- /dev/null +++ b/src/test/rustdoc/inline_local/issue-28537.rs @@ -0,0 +1,27 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[doc(hidden)] +pub mod foo { + pub struct Foo; +} + +mod bar { + pub use self::bar::Bar; + mod bar { + pub struct Bar; + } +} + +// @has issue_28537/struct.Foo.html +pub use foo::Foo; + +// @has issue_28537/struct.Bar.html +pub use self::bar::Bar; From 7c983991d9ec1adb3dc608f4f87c48f5bd46641f Mon Sep 17 00:00:00 2001 From: mitaa Date: Wed, 9 Mar 2016 00:57:13 +0100 Subject: [PATCH 11/23] Remove `feature(globs)` since they are stable --- src/test/run-pass/cci_nested_exe.rs | 2 -- src/test/rustdoc/recursion1.rs | 1 - src/test/rustdoc/recursion2.rs | 1 - src/test/rustdoc/recursion3.rs | 2 -- 4 files changed, 6 deletions(-) diff --git a/src/test/run-pass/cci_nested_exe.rs b/src/test/run-pass/cci_nested_exe.rs index e4f4a4f3a576c..b40c29dd71529 100644 --- a/src/test/run-pass/cci_nested_exe.rs +++ b/src/test/run-pass/cci_nested_exe.rs @@ -11,8 +11,6 @@ // aux-build:cci_nested_lib.rs -#![feature(globs)] - extern crate cci_nested_lib; use cci_nested_lib::*; diff --git a/src/test/rustdoc/recursion1.rs b/src/test/rustdoc/recursion1.rs index 7505d20566dbb..00f7d90fabc38 100644 --- a/src/test/rustdoc/recursion1.rs +++ b/src/test/rustdoc/recursion1.rs @@ -9,7 +9,6 @@ // except according to those terms. #![crate_type = "lib"] -#![feature(globs)] mod m { pub use self::a::Foo; diff --git a/src/test/rustdoc/recursion2.rs b/src/test/rustdoc/recursion2.rs index 7505d20566dbb..00f7d90fabc38 100644 --- a/src/test/rustdoc/recursion2.rs +++ b/src/test/rustdoc/recursion2.rs @@ -9,7 +9,6 @@ // except according to those terms. #![crate_type = "lib"] -#![feature(globs)] mod m { pub use self::a::Foo; diff --git a/src/test/rustdoc/recursion3.rs b/src/test/rustdoc/recursion3.rs index 62a13f76ca4f0..1d9b903a27920 100644 --- a/src/test/rustdoc/recursion3.rs +++ b/src/test/rustdoc/recursion3.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(globs)] - pub mod longhands { pub use super::*; From 1b6d284485802610f35c0655ccff3255abb33e1c Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Wed, 2 Mar 2016 00:58:04 -0500 Subject: [PATCH 12/23] refactor derive-no-std test, add empty struct/enum --- .../derive-no-std.rs | 29 ++++++++++--------- src/test/run-pass/derive-no-std.rs | 22 ++++++++++++++ 2 files changed, 37 insertions(+), 14 deletions(-) rename src/test/{run-pass-fulldeps => auxiliary}/derive-no-std.rs (64%) create mode 100644 src/test/run-pass/derive-no-std.rs diff --git a/src/test/run-pass-fulldeps/derive-no-std.rs b/src/test/auxiliary/derive-no-std.rs similarity index 64% rename from src/test/run-pass-fulldeps/derive-no-std.rs rename to src/test/auxiliary/derive-no-std.rs index 78e9da001f799..f083e10bfdb32 100644 --- a/src/test/run-pass-fulldeps/derive-no-std.rs +++ b/src/test/auxiliary/derive-no-std.rs @@ -8,32 +8,33 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rand, collections, rustc_private)] -#![no_std] +// no-prefer-dynamic -extern crate rand; -extern crate serialize as rustc_serialize; -extern crate collections; +#![crate_type = "rlib"] +#![no_std] // Issue #16803 #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug, Default, Copy)] -struct Foo { - x: u32, +pub struct Foo { + pub x: u32, } #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug, Copy)] -enum Bar { +pub enum Bar { Qux, Quux(u32), } -enum Baz { A=0, B=5, } +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, + Debug, Copy)] +pub enum Void {} +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, + Debug, Copy)] +pub struct Empty; +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, + Debug, Copy)] +pub struct AlsoEmpty {} -fn main() { - Foo { x: 0 }; - Bar::Quux(3); - Baz::A; -} diff --git a/src/test/run-pass/derive-no-std.rs b/src/test/run-pass/derive-no-std.rs new file mode 100644 index 0000000000000..0cbe4f4ebd0ed --- /dev/null +++ b/src/test/run-pass/derive-no-std.rs @@ -0,0 +1,22 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:derive-no-std.rs + +extern crate derive_no_std; +use derive_no_std::*; + +fn main() { + let f = Foo { x: 0 }; + assert_eq!(f.clone(), Foo::default()); + + assert!(Bar::Qux < Bar::Quux(42)); +} + From 2321994d36434e871696abf66e00265f10455995 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Thu, 3 Mar 2016 11:45:58 -0500 Subject: [PATCH 13/23] derive: emit intrinsics::unreachable for impls on empty enums fixes #31574 --- src/libsyntax_ext/deriving/generic/mod.rs | 29 ++++++++++++++--------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index c0237a5d29a41..3896a7ce71462 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -381,6 +381,22 @@ fn find_type_parameters(ty: &ast::Ty, ty_param_names: &[ast::Name]) -> Vec P { + let path = cx.std_path(&["intrinsics", "unreachable"]); + let call = cx.expr_call_global( + sp, path, vec![]); + let unreachable = cx.expr_block(P(ast::Block { + stmts: vec![], + expr: Some(call), + id: ast::DUMMY_NODE_ID, + rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated), + span: sp })); + + unreachable +} + impl<'a> TraitDef<'a> { pub fn expand(&self, cx: &mut ExtCtxt, @@ -1297,16 +1313,7 @@ impl<'a> MethodDef<'a> { //Since we know that all the arguments will match if we reach the match expression we //add the unreachable intrinsics as the result of the catch all which should help llvm //in optimizing it - let path = cx.std_path(&["intrinsics", "unreachable"]); - let call = cx.expr_call_global( - sp, path, vec![]); - let unreachable = cx.expr_block(P(ast::Block { - stmts: vec![], - expr: Some(call), - id: ast::DUMMY_NODE_ID, - rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated), - span: sp })); - match_arms.push(cx.arm(sp, vec![cx.pat_wild(sp)], unreachable)); + match_arms.push(cx.arm(sp, vec![cx.pat_wild(sp)], expr_unreachable_intrinsic(cx, sp))); // Final wrinkle: the self_args are expressions that deref // down to desired l-values, but we cannot actually deref @@ -1382,7 +1389,7 @@ impl<'a> MethodDef<'a> { // derive Debug on such a type could here generate code // that needs the feature gate enabled.) - cx.expr_unreachable(sp) + expr_unreachable_intrinsic(cx, sp) } else { From 0ddc17d5bb6757dc49136c0de3168d9cdb00f6e3 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 10 Mar 2016 05:21:00 -0500 Subject: [PATCH 14/23] Add comment explaining purpose of test --- src/test/compile-fail/issue-30580.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/compile-fail/issue-30580.rs b/src/test/compile-fail/issue-30580.rs index 908a2d47401e5..88d4aef6d9ddc 100644 --- a/src/test/compile-fail/issue-30580.rs +++ b/src/test/compile-fail/issue-30580.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Test that we do not see uninformative region-related errors +// when we get some basic type-checking failure. See #30580. + pub struct Foo { a: u32 } pub struct Pass<'a, 'tcx: 'a>(&'a mut &'a (), &'a &'tcx ()); From 700b22643e290bb23f4639e1ca13cba6d7a08080 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Thu, 3 Mar 2016 14:55:24 -0500 Subject: [PATCH 15/23] derive: assume enum repr defaults to i64 It was originally intended to be i32, but it isn't. Fixes #31886. --- src/libsyntax_ext/deriving/generic/mod.rs | 2 +- src/test/run-pass/enum-discrim-autosizing.rs | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 3896a7ce71462..119b88befd1d8 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -757,7 +757,7 @@ impl<'a> TraitDef<'a> { fn find_repr_type_name(diagnostic: &Handler, type_attrs: &[ast::Attribute]) -> &'static str { - let mut repr_type_name = "i32"; + let mut repr_type_name = "i64"; for a in type_attrs { for r in &attr::find_repr_attrs(diagnostic, a) { repr_type_name = match *r { diff --git a/src/test/run-pass/enum-discrim-autosizing.rs b/src/test/run-pass/enum-discrim-autosizing.rs index 99e44735d0f03..f027689a64a54 100644 --- a/src/test/run-pass/enum-discrim-autosizing.rs +++ b/src/test/run-pass/enum-discrim-autosizing.rs @@ -46,6 +46,7 @@ enum Ei64 { Bi64 = 0x8000_0000 } +#[derive(PartialEq)] enum Eu64 { Au64 = 0, Bu64 = 0x8000_0000_0000_0000 @@ -60,4 +61,7 @@ pub fn main() { assert_eq!(size_of::(), 4); assert_eq!(size_of::(), 8); assert_eq!(size_of::(), 8); + + // ensure no i32 collisions + assert!(Eu64::Au64 != Eu64::Bu64); } From c1c363af57fb3883552de884bcb31afd6c71a22a Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Sat, 5 Mar 2016 14:51:24 -0500 Subject: [PATCH 16/23] add #[derive(Hash)] test for #21714 --- src/test/run-pass/deriving-hash.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/test/run-pass/deriving-hash.rs b/src/test/run-pass/deriving-hash.rs index 69e9816ab9486..ea19510680f63 100644 --- a/src/test/run-pass/deriving-hash.rs +++ b/src/test/run-pass/deriving-hash.rs @@ -12,6 +12,7 @@ #![feature(hash_default)] use std::hash::{Hash, SipHasher, Hasher}; +use std::mem::size_of; #[derive(Hash)] struct Person { @@ -20,12 +21,30 @@ struct Person { phone: usize, } +#[derive(Hash)] +enum E { A=1, B } + fn hash(t: &T) -> u64 { let mut s = SipHasher::new_with_keys(0, 0); t.hash(&mut s); s.finish() } +struct FakeHasher<'a>(&'a mut Vec); +impl<'a> Hasher for FakeHasher<'a> { + fn finish(&self) -> u64 { + unimplemented!() + } + + fn write(&mut self, bytes: &[u8]) { + self.0.extend(bytes); + } +} + +fn fake_hash(v: &mut Vec, e: E) { + e.hash(&mut FakeHasher(v)); +} + fn main() { let person1 = Person { id: 5, @@ -39,4 +58,11 @@ fn main() { }; assert_eq!(hash(&person1), hash(&person1)); assert!(hash(&person1) != hash(&person2)); + + // test #21714 + let mut va = vec![]; + let mut vb = vec![]; + fake_hash(&mut va, E::A); + fake_hash(&mut vb, E::B); + assert!(va != vb); } From 7074a8826f9cd3f2ae49e462248b8fa74c7caa00 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Mon, 7 Mar 2016 13:05:12 -0500 Subject: [PATCH 17/23] fix #21714 by using discriminant_value in #[derive(Hash)] This is the same approach taken in #24270, except that this should not be a breaking change because it only changes the output of hash functions, which nobody should be relying on. --- src/libsyntax_ext/deriving/hash.rs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/libsyntax_ext/deriving/hash.rs b/src/libsyntax_ext/deriving/hash.rs index bf8aa8fb23deb..96c4e6536e783 100644 --- a/src/libsyntax_ext/deriving/hash.rs +++ b/src/libsyntax_ext/deriving/hash.rs @@ -11,7 +11,7 @@ use deriving::generic::*; use deriving::generic::ty::*; -use syntax::ast::{MetaItem, Expr, Mutability}; +use syntax::ast::{self, MetaItem, Expr, Mutability}; use syntax::codemap::Span; use syntax::ext::base::{ExtCtxt, Annotatable}; use syntax::ext::build::AstBuilder; @@ -77,15 +77,18 @@ fn hash_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) let fields = match *substr.fields { Struct(_, ref fs) => fs, - EnumMatching(index, variant, ref fs) => { - // Determine the discriminant. We will feed this value to the byte - // iteration function. - let discriminant = match variant.node.disr_expr { - Some(ref d) => d.clone(), - None => cx.expr_usize(trait_span, index) - }; + EnumMatching(_, _, ref fs) => { + let path = cx.std_path(&["intrinsics", "discriminant_value"]); + let call = cx.expr_call_global( + trait_span, path, vec![cx.expr_self(trait_span)]); + let variant_value = cx.expr_block(P(ast::Block { + stmts: vec![], + expr: Some(call), + id: ast::DUMMY_NODE_ID, + rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated), + span: trait_span })); - stmts.push(call_hash(trait_span, discriminant)); + stmts.push(call_hash(trait_span, variant_value)); fs } From bc53d91d7d23538407865b3a9d5f51b26b745a3e Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Mon, 7 Mar 2016 18:35:01 -0500 Subject: [PATCH 18/23] fix FIXME(#6449) in #[derive(PartialOrd, Ord)] This replaces some `if`s with `match`es. This was originally not possible because using a global path in a match statement caused a "non-constant path in constant expr" ICE. The issue is long since closed, though you still hit it (as an error now, not an ICE) if you try to generate match patterns using pat_lit(expr_path). But it works when constructing the patterns more carefully. --- src/libsyntax_ext/deriving/cmp/ord.rs | 50 ++++++++--------- src/libsyntax_ext/deriving/cmp/partial_ord.rs | 53 +++++++++---------- 2 files changed, 48 insertions(+), 55 deletions(-) diff --git a/src/libsyntax_ext/deriving/cmp/ord.rs b/src/libsyntax_ext/deriving/cmp/ord.rs index 2fa847ee430d8..f4082e0b123bf 100644 --- a/src/libsyntax_ext/deriving/cmp/ord.rs +++ b/src/libsyntax_ext/deriving/cmp/ord.rs @@ -73,36 +73,31 @@ pub fn cs_cmp(cx: &mut ExtCtxt, span: Span, /* Builds: - let __test = ::std::cmp::Ord::cmp(&self_field1, &other_field1); - if other == ::std::cmp::Ordering::Equal { - let __test = ::std::cmp::Ord::cmp(&self_field2, &other_field2); - if __test == ::std::cmp::Ordering::Equal { - ... - } else { - __test - } - } else { - __test + match ::std::cmp::Ord::cmp(&self_field1, &other_field1) { + ::std::cmp::Ordering::Equal => + match ::std::cmp::Ord::cmp(&self_field2, &other_field2) { + ::std::cmp::Ordering::Equal => { + ... + } + __test => __test + }, + __test => __test } - - FIXME #6449: These `if`s could/should be `match`es. */ cs_fold( // foldr nests the if-elses correctly, leaving the first field // as the outermost one, and the last as the innermost. false, |cx, span, old, self_f, other_fs| { - // let __test = new; - // if __test == ::std::cmp::Ordering::Equal { - // old - // } else { - // __test + // match new { + // ::std::cmp::Ordering::Equal => old, + // __test => __test // } let new = { let other_f = match (other_fs.len(), other_fs.get(0)) { (1, Some(o_f)) => o_f, - _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"), + _ => cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`"), }; let args = vec![ @@ -113,20 +108,21 @@ pub fn cs_cmp(cx: &mut ExtCtxt, span: Span, cx.expr_call_global(span, cmp_path.clone(), args) }; - let assign = cx.stmt_let(span, false, test_id, new); + let eq_arm = cx.arm(span, + vec![cx.pat_enum(span, + equals_path.clone(), + vec![])], + old); + let neq_arm = cx.arm(span, + vec![cx.pat_ident(span, test_id)], + cx.expr_ident(span, test_id)); - let cond = cx.expr_binary(span, BinOpKind::Eq, - cx.expr_ident(span, test_id), - cx.expr_path(equals_path.clone())); - let if_ = cx.expr_if(span, - cond, - old, Some(cx.expr_ident(span, test_id))); - cx.expr_block(cx.block(span, vec!(assign), Some(if_))) + cx.expr_match(span, new, vec![eq_arm, neq_arm]) }, cx.expr_path(equals_path.clone()), Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| { if self_args.len() != 2 { - cx.span_bug(span, "not exactly 2 arguments in `derives(Ord)`") + cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`") } else { ordering_collapsed(cx, span, tag_tuple) } diff --git a/src/libsyntax_ext/deriving/cmp/partial_ord.rs b/src/libsyntax_ext/deriving/cmp/partial_ord.rs index e857f7d52f912..3353addebc971 100644 --- a/src/libsyntax_ext/deriving/cmp/partial_ord.rs +++ b/src/libsyntax_ext/deriving/cmp/partial_ord.rs @@ -110,38 +110,33 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, let test_id = cx.ident_of("__test"); let ordering = cx.path_global(span, cx.std_path(&["cmp", "Ordering", "Equal"])); - let ordering = cx.expr_path(ordering); - let equals_expr = cx.expr_some(span, ordering); + let ordering_expr = cx.expr_path(ordering.clone()); + let equals_expr = cx.expr_some(span, ordering_expr); let partial_cmp_path = cx.std_path(&["cmp", "PartialOrd", "partial_cmp"]); /* Builds: - let __test = ::std::cmp::PartialOrd::partial_cmp(&self_field1, &other_field1); - if __test == ::std::option::Option::Some(::std::cmp::Ordering::Equal) { - let __test = ::std::cmp::PartialOrd::partial_cmp(&self_field2, &other_field2); - if __test == ::std::option::Option::Some(::std::cmp::Ordering::Equal) { - ... - } else { - __test - } - } else { - __test + match ::std::cmp::PartialOrd::partial_cmp(&self_field1, &other_field1) { + ::std::option::Option::Some(::std::cmp::Ordering::Equal) => + match ::std::cmp::PartialOrd::partial_cmp(&self_field2, &other_field2) { + ::std::option::Option::Some(::std::cmp::Ordering::Equal) => { + ... + } + __test => __test + }, + __test => __test } - - FIXME #6449: These `if`s could/should be `match`es. */ cs_fold( // foldr nests the if-elses correctly, leaving the first field // as the outermost one, and the last as the innermost. false, |cx, span, old, self_f, other_fs| { - // let __test = new; - // if __test == Some(::std::cmp::Ordering::Equal) { - // old - // } else { - // __test + // match new { + // Some(::std::cmp::Ordering::Equal) => old, + // __test => __test // } let new = { @@ -158,15 +153,17 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, cx.expr_call_global(span, partial_cmp_path.clone(), args) }; - let assign = cx.stmt_let(span, false, test_id, new); - - let cond = cx.expr_binary(span, BinOpKind::Eq, - cx.expr_ident(span, test_id), - equals_expr.clone()); - let if_ = cx.expr_if(span, - cond, - old, Some(cx.expr_ident(span, test_id))); - cx.expr_block(cx.block(span, vec!(assign), Some(if_))) + let eq_arm = cx.arm(span, + vec![cx.pat_some(span, + cx.pat_enum(span, + ordering.clone(), + vec![]))], + old); + let neq_arm = cx.arm(span, + vec![cx.pat_ident(span, test_id)], + cx.expr_ident(span, test_id)); + + cx.expr_match(span, new, vec![eq_arm, neq_arm]) }, equals_expr.clone(), Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| { From fe999e3337561d64bcc26709e10457554226a45c Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Mon, 7 Mar 2016 19:07:06 -0500 Subject: [PATCH 19/23] derive: remove most __ strings FIXME(#2810) This changes local variable names in all derives to remove leading double-underscores. As far as I can tell, this doesn't break anything because there is no user code in these generated functions except for struct, field and type parameter names, and this doesn't cause shadowing of those. But I am still a bit nervous. --- src/libsyntax_ext/deriving/cmp/ord.rs | 8 +- src/libsyntax_ext/deriving/cmp/partial_ord.rs | 8 +- src/libsyntax_ext/deriving/generic/mod.rs | 80 +++++++++---------- 3 files changed, 48 insertions(+), 48 deletions(-) diff --git a/src/libsyntax_ext/deriving/cmp/ord.rs b/src/libsyntax_ext/deriving/cmp/ord.rs index f4082e0b123bf..a69d57423a22c 100644 --- a/src/libsyntax_ext/deriving/cmp/ord.rs +++ b/src/libsyntax_ext/deriving/cmp/ord.rs @@ -64,7 +64,7 @@ pub fn ordering_collapsed(cx: &mut ExtCtxt, pub fn cs_cmp(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { - let test_id = cx.ident_of("__test"); + let test_id = cx.ident_of("cmp"); let equals_path = cx.path_global(span, cx.std_path(&["cmp", "Ordering", "Equal"])); @@ -79,9 +79,9 @@ pub fn cs_cmp(cx: &mut ExtCtxt, span: Span, ::std::cmp::Ordering::Equal => { ... } - __test => __test + cmp => cmp }, - __test => __test + cmp => cmp } */ cs_fold( @@ -91,7 +91,7 @@ pub fn cs_cmp(cx: &mut ExtCtxt, span: Span, |cx, span, old, self_f, other_fs| { // match new { // ::std::cmp::Ordering::Equal => old, - // __test => __test + // cmp => cmp // } let new = { diff --git a/src/libsyntax_ext/deriving/cmp/partial_ord.rs b/src/libsyntax_ext/deriving/cmp/partial_ord.rs index 3353addebc971..b3864a6c2e79e 100644 --- a/src/libsyntax_ext/deriving/cmp/partial_ord.rs +++ b/src/libsyntax_ext/deriving/cmp/partial_ord.rs @@ -107,7 +107,7 @@ pub fn some_ordering_collapsed(cx: &mut ExtCtxt, pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { - let test_id = cx.ident_of("__test"); + let test_id = cx.ident_of("cmp"); let ordering = cx.path_global(span, cx.std_path(&["cmp", "Ordering", "Equal"])); let ordering_expr = cx.expr_path(ordering.clone()); @@ -124,9 +124,9 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, ::std::option::Option::Some(::std::cmp::Ordering::Equal) => { ... } - __test => __test + cmp => cmp }, - __test => __test + cmp => cmp } */ cs_fold( @@ -136,7 +136,7 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, |cx, span, old, self_f, other_fs| { // match new { // Some(::std::cmp::Ordering::Equal) => old, - // __test => __test + // cmp => cmp // } let new = { diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 119b88befd1d8..2f72db48b9a33 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -156,14 +156,14 @@ //! //! ```{.text} //! EnumNonMatchingCollapsed( -//! vec![, ], +//! vec![, ], //! &[, ], -//! &[, ]) +//! &[, ]) //! ``` //! //! It is the same for when the arguments are flipped to `C1 {x}` and //! `C0(a)`; the only difference is what the values of the identifiers -//! and will +//! and will //! be in the generated code. //! //! `EnumNonMatchingCollapsed` deliberately provides far less information @@ -842,7 +842,7 @@ impl<'a> MethodDef<'a> { for (i, ty) in self.args.iter().enumerate() { let ast_ty = ty.to_ty(cx, trait_.span, type_ident, generics); - let ident = cx.ident_of(&format!("__arg_{}", i)); + let ident = cx.ident_of(&format!("arg_{}", i)); arg_tys.push((ident, ast_ty)); let arg_expr = cx.expr_ident(trait_.span, ident); @@ -927,12 +927,12 @@ impl<'a> MethodDef<'a> { /// /// // equivalent to: /// impl PartialEq for A { - /// fn eq(&self, __arg_1: &A) -> bool { + /// fn eq(&self, arg_1: &A) -> bool { /// match *self { - /// A {x: ref __self_0_0, y: ref __self_0_1} => { - /// match *__arg_1 { - /// A {x: ref __self_1_0, y: ref __self_1_1} => { - /// __self_0_0.eq(__self_1_0) && __self_0_1.eq(__self_1_1) + /// A {x: ref self_0_0, y: ref self_0_1} => { + /// match *arg_1 { + /// A {x: ref self_1_0, y: ref self_1_1} => { + /// self_0_0.eq(self_1_0) && self_0_1.eq(self_1_1) /// } /// } /// } @@ -958,7 +958,7 @@ impl<'a> MethodDef<'a> { trait_.create_struct_pattern(cx, struct_path, struct_def, - &format!("__self_{}", + &format!("self_{}", i), ast::Mutability::Immutable); patterns.push(pat); @@ -1036,14 +1036,14 @@ impl<'a> MethodDef<'a> { /// // is equivalent to /// /// impl PartialEq for A { - /// fn eq(&self, __arg_1: &A) -> ::bool { - /// match (&*self, &*__arg_1) { + /// fn eq(&self, arg_1: &A) -> ::bool { + /// match (&*self, &*arg_1) { /// (&A1, &A1) => true, - /// (&A2(ref __self_0), - /// &A2(ref __arg_1_0)) => (*__self_0).eq(&(*__arg_1_0)), + /// (&A2(ref self_0), + /// &A2(ref arg_1_0)) => (*self_0).eq(&(*arg_1_0)), /// _ => { - /// let __self_vi = match *self { A1(..) => 0, A2(..) => 1 }; - /// let __arg_1_vi = match *__arg_1 { A1(..) => 0, A2(..) => 1 }; + /// let self_vi = match *self { A1(..) => 0, A2(..) => 1 }; + /// let arg_1_vi = match *arg_1 { A1(..) => 0, A2(..) => 1 }; /// false /// } /// } @@ -1051,10 +1051,10 @@ impl<'a> MethodDef<'a> { /// } /// ``` /// - /// (Of course `__self_vi` and `__arg_1_vi` are unused for + /// (Of course `self_vi` and `arg_1_vi` are unused for /// `PartialEq`, and those subcomputations will hopefully be removed - /// as their results are unused. The point of `__self_vi` and - /// `__arg_1_vi` is for `PartialOrd`; see #15503.) + /// as their results are unused. The point of `self_vi` and + /// `arg_1_vi` is for `PartialOrd`; see #15503.) fn expand_enum_method_body<'b>(&self, cx: &mut ExtCtxt, trait_: &TraitDef<'b>, @@ -1085,14 +1085,14 @@ impl<'a> MethodDef<'a> { /// for each of the self-args, carried in precomputed variables. /// ```{.text} - /// let __self0_vi = unsafe { + /// let self0_vi = unsafe { /// std::intrinsics::discriminant_value(&self) } as i32; - /// let __self1_vi = unsafe { - /// std::intrinsics::discriminant_value(&__arg1) } as i32; - /// let __self2_vi = unsafe { - /// std::intrinsics::discriminant_value(&__arg2) } as i32; + /// let self1_vi = unsafe { + /// std::intrinsics::discriminant_value(&arg1) } as i32; + /// let self2_vi = unsafe { + /// std::intrinsics::discriminant_value(&arg2) } as i32; /// - /// if __self0_vi == __self1_vi && __self0_vi == __self2_vi && ... { + /// if self0_vi == self1_vi && self0_vi == self2_vi && ... { /// match (...) { /// (Variant1, Variant1, ...) => Body1 /// (Variant2, Variant2, ...) => Body2, @@ -1120,9 +1120,9 @@ impl<'a> MethodDef<'a> { let self_arg_names = self_args.iter().enumerate() .map(|(arg_count, _self_arg)| { if arg_count == 0 { - "__self".to_string() + "self".to_string() } else { - format!("__arg_{}", arg_count) + format!("arg_{}", arg_count) } }) .collect::>(); @@ -1259,17 +1259,17 @@ impl<'a> MethodDef<'a> { // with three Self args, builds three statements: // // ``` - // let __self0_vi = unsafe { + // let self0_vi = unsafe { // std::intrinsics::discriminant_value(&self) } as i32; - // let __self1_vi = unsafe { - // std::intrinsics::discriminant_value(&__arg1) } as i32; - // let __self2_vi = unsafe { - // std::intrinsics::discriminant_value(&__arg2) } as i32; + // let self1_vi = unsafe { + // std::intrinsics::discriminant_value(&arg1) } as i32; + // let self2_vi = unsafe { + // std::intrinsics::discriminant_value(&arg2) } as i32; // ``` let mut index_let_stmts: Vec = Vec::new(); //We also build an expression which checks whether all discriminants are equal - // discriminant_test = __self0_vi == __self1_vi && __self0_vi == __self2_vi && ... + // discriminant_test = self0_vi == self1_vi && self0_vi == self2_vi && ... let mut discriminant_test = cx.expr_bool(sp, true); let target_type_name = @@ -1319,7 +1319,7 @@ impl<'a> MethodDef<'a> { // down to desired l-values, but we cannot actually deref // them when they are fed as r-values into a tuple // expression; here add a layer of borrowing, turning - // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`. + // `(*self, *arg_0, ...)` into `(&*self, &*arg_0, ...)`. let borrowed_self_args = self_args.move_map(|self_arg| cx.expr_addr_of(sp, self_arg)); let match_arg = cx.expr(sp, ast::ExprKind::Tup(borrowed_self_args)); @@ -1333,7 +1333,7 @@ impl<'a> MethodDef<'a> { // } // } // else { - // + // // } let all_match = cx.expr_match(sp, match_arg, match_arms); let arm_expr = cx.expr_if(sp, discriminant_test, all_match, Some(arm_expr)); @@ -1357,8 +1357,8 @@ impl<'a> MethodDef<'a> { // error-prone, since the catch-all as defined above would // generate code like this: // - // _ => { let __self0 = match *self { }; - // let __self1 = match *__arg_0 { }; + // _ => { let self0 = match *self { }; + // let self1 = match *arg_0 { }; // } // // Which is yields bindings for variables which type @@ -1397,7 +1397,7 @@ impl<'a> MethodDef<'a> { // down to desired l-values, but we cannot actually deref // them when they are fed as r-values into a tuple // expression; here add a layer of borrowing, turning - // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`. + // `(*self, *arg_0, ...)` into `(&*self, &*arg_0, ...)`. let borrowed_self_args = self_args.move_map(|self_arg| cx.expr_addr_of(sp, self_arg)); let match_arg = cx.expr(sp, ast::ExprKind::Tup(borrowed_self_args)); cx.expr_match(sp, match_arg, match_arms) @@ -1611,8 +1611,8 @@ pub fn cs_fold(use_foldl: bool, /// process the collected results. i.e. /// /// ```ignore -/// f(cx, span, vec![self_1.method(__arg_1_1, __arg_2_1), -/// self_2.method(__arg_1_2, __arg_2_2)]) +/// f(cx, span, vec![self_1.method(arg_1_1, arg_2_1), +/// self_2.method(arg_1_2, arg_2_2)]) /// ``` #[inline] pub fn cs_same_method(f: F, From c12e906398381b2a4e414fbd333a06e06ae035d9 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Tue, 8 Mar 2016 13:24:28 -0500 Subject: [PATCH 20/23] derive: improve hygiene for type parameters (see #2810) When deriving Hash, RustcEncodable and RustcDecodable, the syntax extension needs a type parameter to use in the inner method. They used to use __H, __S and __D respectively. If this conflicts with a type parameter already declared for the item, bad times result (see the test). There is no hygiene for type parameters, but this commit introduces a better heuristic by concatenating the names of all extant type parameters (and prepending __H). --- src/libsyntax_ext/deriving/cmp/ord.rs | 2 +- src/libsyntax_ext/deriving/decodable.rs | 12 +++++----- src/libsyntax_ext/deriving/encodable.rs | 12 +++++----- src/libsyntax_ext/deriving/hash.rs | 8 +++++-- src/libsyntax_ext/deriving/mod.rs | 29 +++++++++++++++++++++---- src/test/run-pass/deriving-hash.rs | 4 ++++ 6 files changed, 50 insertions(+), 17 deletions(-) diff --git a/src/libsyntax_ext/deriving/cmp/ord.rs b/src/libsyntax_ext/deriving/cmp/ord.rs index a69d57423a22c..a7e156c5f6820 100644 --- a/src/libsyntax_ext/deriving/cmp/ord.rs +++ b/src/libsyntax_ext/deriving/cmp/ord.rs @@ -11,7 +11,7 @@ use deriving::generic::*; use deriving::generic::ty::*; -use syntax::ast::{MetaItem, Expr, BinOpKind, self}; +use syntax::ast::{MetaItem, Expr, self}; use syntax::codemap::Span; use syntax::ext::base::{ExtCtxt, Annotatable}; use syntax::ext::build::AstBuilder; diff --git a/src/libsyntax_ext/deriving/decodable.rs b/src/libsyntax_ext/deriving/decodable.rs index 092f8548966da..49f14c937e953 100644 --- a/src/libsyntax_ext/deriving/decodable.rs +++ b/src/libsyntax_ext/deriving/decodable.rs @@ -10,6 +10,7 @@ //! The compiler code necessary for `#[derive(Decodable)]`. See encodable.rs for more. +use deriving; use deriving::generic::*; use deriving::generic::ty::*; @@ -54,6 +55,8 @@ fn expand_deriving_decodable_imp(cx: &mut ExtCtxt, return } + let typaram = &*deriving::hygienic_type_parameter(item, "__D"); + let trait_def = TraitDef { span: span, attributes: Vec::new(), @@ -66,18 +69,17 @@ fn expand_deriving_decodable_imp(cx: &mut ExtCtxt, name: "decode", generics: LifetimeBounds { lifetimes: Vec::new(), - bounds: vec!(("__D", vec!(Path::new_( - vec!(krate, "Decoder"), None, - vec!(), true)))) + bounds: vec![(typaram, + vec![Path::new_(vec!(krate, "Decoder"), None, vec!(), true)])] }, explicit_self: None, - args: vec!(Ptr(Box::new(Literal(Path::new_local("__D"))), + args: vec!(Ptr(Box::new(Literal(Path::new_local(typaram))), Borrowed(None, Mutability::Mutable))), ret_ty: Literal(Path::new_( pathvec_std!(cx, core::result::Result), None, vec!(Box::new(Self_), Box::new(Literal(Path::new_( - vec!["__D", "Error"], None, vec![], false + vec![typaram, "Error"], None, vec![], false )))), true )), diff --git a/src/libsyntax_ext/deriving/encodable.rs b/src/libsyntax_ext/deriving/encodable.rs index 8262a04e9ce17..a05bd7869b2a9 100644 --- a/src/libsyntax_ext/deriving/encodable.rs +++ b/src/libsyntax_ext/deriving/encodable.rs @@ -88,6 +88,7 @@ //! } //! ``` +use deriving; use deriving::generic::*; use deriving::generic::ty::*; @@ -130,6 +131,8 @@ fn expand_deriving_encodable_imp(cx: &mut ExtCtxt, return; } + let typaram = &*deriving::hygienic_type_parameter(item, "__S"); + let trait_def = TraitDef { span: span, attributes: Vec::new(), @@ -142,18 +145,17 @@ fn expand_deriving_encodable_imp(cx: &mut ExtCtxt, name: "encode", generics: LifetimeBounds { lifetimes: Vec::new(), - bounds: vec!(("__S", vec!(Path::new_( - vec!(krate, "Encoder"), None, - vec!(), true)))) + bounds: vec![(typaram, + vec![Path::new_(vec![krate, "Encoder"], None, vec!(), true)])] }, explicit_self: borrowed_explicit_self(), - args: vec!(Ptr(Box::new(Literal(Path::new_local("__S"))), + args: vec!(Ptr(Box::new(Literal(Path::new_local(typaram))), Borrowed(None, Mutability::Mutable))), ret_ty: Literal(Path::new_( pathvec_std!(cx, core::result::Result), None, vec!(Box::new(Tuple(Vec::new())), Box::new(Literal(Path::new_( - vec!["__S", "Error"], None, vec![], false + vec![typaram, "Error"], None, vec![], false )))), true )), diff --git a/src/libsyntax_ext/deriving/hash.rs b/src/libsyntax_ext/deriving/hash.rs index 96c4e6536e783..9368658648910 100644 --- a/src/libsyntax_ext/deriving/hash.rs +++ b/src/libsyntax_ext/deriving/hash.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use deriving; use deriving::generic::*; use deriving::generic::ty::*; @@ -26,7 +27,10 @@ pub fn expand_deriving_hash(cx: &mut ExtCtxt, let path = Path::new_(pathvec_std!(cx, core::hash::Hash), None, vec!(), true); - let arg = Path::new_local("__H"); + + let typaram = &*deriving::hygienic_type_parameter(item, "__H"); + + let arg = Path::new_local(typaram); let hash_trait_def = TraitDef { span: span, attributes: Vec::new(), @@ -39,7 +43,7 @@ pub fn expand_deriving_hash(cx: &mut ExtCtxt, name: "hash", generics: LifetimeBounds { lifetimes: Vec::new(), - bounds: vec![("__H", + bounds: vec![(typaram, vec![path_std!(cx, core::hash::Hasher)])], }, explicit_self: borrowed_explicit_self(), diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index 4e2142f1fb482..75de5c56ea139 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -9,11 +9,8 @@ // except according to those terms. //! The compiler code necessary to implement the `#[derive]` extensions. -//! -//! FIXME (#2810): hygiene. Search for "__" strings (in other files too). We also assume "extra" is -//! the standard library, and "std" is the core library. -use syntax::ast::{MetaItem, MetaItemKind}; +use syntax::ast::{MetaItem, MetaItemKind, self}; use syntax::attr::AttrMetaMethods; use syntax::ext::base::{ExtCtxt, SyntaxEnv, Annotatable}; use syntax::ext::base::{MultiDecorator, MultiItemDecorator, MultiModifier}; @@ -197,3 +194,27 @@ fn warn_if_deprecated(ecx: &mut ExtCtxt, sp: Span, name: &str) { name, replacement)); } } + +/// Construct a name for the inner type parameter that can't collide with any type parameters of +/// the item. This is achieved by starting with a base and then concatenating the names of all +/// other type parameters. +// FIXME(aburka): use real hygiene when that becomes possible +fn hygienic_type_parameter(item: &Annotatable, base: &str) -> String { + let mut typaram = String::from(base); + if let Annotatable::Item(ref item) = *item { + match item.node { + ast::ItemKind::Struct(_, ast::Generics { ref ty_params, .. }) | + ast::ItemKind::Enum(_, ast::Generics { ref ty_params, .. }) => { + + for ty in ty_params.iter() { + typaram.push_str(&ty.ident.name.as_str()); + } + } + + _ => {} + } + } + + typaram +} + diff --git a/src/test/run-pass/deriving-hash.rs b/src/test/run-pass/deriving-hash.rs index ea19510680f63..c40d0683657a8 100644 --- a/src/test/run-pass/deriving-hash.rs +++ b/src/test/run-pass/deriving-hash.rs @@ -24,6 +24,10 @@ struct Person { #[derive(Hash)] enum E { A=1, B } +// test for hygiene name collisions +#[derive(Hash)] struct __H__H; +#[derive(Hash)] enum Collision<__H> { __H { __H__H: __H } } + fn hash(t: &T) -> u64 { let mut s = SipHasher::new_with_keys(0, 0); t.hash(&mut s); From 8cccdd006bfb19f0e35ad0994614c01fe355b190 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Thu, 10 Mar 2016 00:31:19 -0500 Subject: [PATCH 21/23] deriving: factor out discriminant_value construction --- src/libsyntax_ext/deriving/generic/mod.rs | 38 +++++++---------------- src/libsyntax_ext/deriving/hash.rs | 15 +++------ src/libsyntax_ext/deriving/mod.rs | 17 ++++++++++ 3 files changed, 33 insertions(+), 37 deletions(-) diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 2f72db48b9a33..93fcfa4cc6372 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -209,6 +209,8 @@ use syntax::ptr::P; use self::ty::{LifetimeBounds, Path, Ptr, PtrTy, Self_, Ty}; +use deriving; + pub mod ty; pub struct TraitDef<'a> { @@ -381,22 +383,6 @@ fn find_type_parameters(ty: &ast::Ty, ty_param_names: &[ast::Name]) -> Vec P { - let path = cx.std_path(&["intrinsics", "unreachable"]); - let call = cx.expr_call_global( - sp, path, vec![]); - let unreachable = cx.expr_block(P(ast::Block { - stmts: vec![], - expr: Some(call), - id: ast::DUMMY_NODE_ID, - rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated), - span: sp })); - - unreachable -} - impl<'a> TraitDef<'a> { pub fn expand(&self, cx: &mut ExtCtxt, @@ -1277,15 +1263,11 @@ impl<'a> MethodDef<'a> { let mut first_ident = None; for (&ident, self_arg) in vi_idents.iter().zip(&self_args) { - let path = cx.std_path(&["intrinsics", "discriminant_value"]); - let call = cx.expr_call_global( - sp, path, vec![cx.expr_addr_of(sp, self_arg.clone())]); - let variant_value = cx.expr_block(P(ast::Block { - stmts: vec![], - expr: Some(call), - id: ast::DUMMY_NODE_ID, - rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated), - span: sp })); + let self_addr = cx.expr_addr_of(sp, self_arg.clone()); + let variant_value = deriving::call_intrinsic(cx, + sp, + "discriminant_value", + vec![self_addr]); let target_ty = cx.ty_ident(sp, cx.ident_of(target_type_name)); let variant_disr = cx.expr_cast(sp, variant_value, target_ty); @@ -1313,7 +1295,9 @@ impl<'a> MethodDef<'a> { //Since we know that all the arguments will match if we reach the match expression we //add the unreachable intrinsics as the result of the catch all which should help llvm //in optimizing it - match_arms.push(cx.arm(sp, vec![cx.pat_wild(sp)], expr_unreachable_intrinsic(cx, sp))); + match_arms.push(cx.arm(sp, + vec![cx.pat_wild(sp)], + deriving::call_intrinsic(cx, sp, "unreachable", vec![]))); // Final wrinkle: the self_args are expressions that deref // down to desired l-values, but we cannot actually deref @@ -1389,7 +1373,7 @@ impl<'a> MethodDef<'a> { // derive Debug on such a type could here generate code // that needs the feature gate enabled.) - expr_unreachable_intrinsic(cx, sp) + deriving::call_intrinsic(cx, sp, "unreachable", vec![]) } else { diff --git a/src/libsyntax_ext/deriving/hash.rs b/src/libsyntax_ext/deriving/hash.rs index 9368658648910..c37ae116d379b 100644 --- a/src/libsyntax_ext/deriving/hash.rs +++ b/src/libsyntax_ext/deriving/hash.rs @@ -12,7 +12,7 @@ use deriving; use deriving::generic::*; use deriving::generic::ty::*; -use syntax::ast::{self, MetaItem, Expr, Mutability}; +use syntax::ast::{MetaItem, Expr, Mutability}; use syntax::codemap::Span; use syntax::ext::base::{ExtCtxt, Annotatable}; use syntax::ext::build::AstBuilder; @@ -82,15 +82,10 @@ fn hash_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) let fields = match *substr.fields { Struct(_, ref fs) => fs, EnumMatching(_, _, ref fs) => { - let path = cx.std_path(&["intrinsics", "discriminant_value"]); - let call = cx.expr_call_global( - trait_span, path, vec![cx.expr_self(trait_span)]); - let variant_value = cx.expr_block(P(ast::Block { - stmts: vec![], - expr: Some(call), - id: ast::DUMMY_NODE_ID, - rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated), - span: trait_span })); + let variant_value = deriving::call_intrinsic(cx, + trait_span, + "discriminant_value", + vec![cx.expr_self(trait_span)]); stmts.push(call_hash(trait_span, variant_value)); diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index 75de5c56ea139..615cb1de0f475 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -18,6 +18,7 @@ use syntax::ext::build::AstBuilder; use syntax::feature_gate; use syntax::codemap::Span; use syntax::parse::token::{intern, intern_and_get_ident}; +use syntax::ptr::P; macro_rules! pathvec { ($($x:ident)::+) => ( @@ -218,3 +219,19 @@ fn hygienic_type_parameter(item: &Annotatable, base: &str) -> String { typaram } +/// Constructs an expression that calls an intrinsic +fn call_intrinsic(cx: &ExtCtxt, + span: Span, + intrinsic: &str, + args: Vec>) -> P { + let path = cx.std_path(&["intrinsics", intrinsic]); + let call = cx.expr_call_global(span, path, args); + + cx.expr_block(P(ast::Block { + stmts: vec![], + expr: Some(call), + id: ast::DUMMY_NODE_ID, + rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated), + span: span })) +} + From e926f281dfc9baec0e01fb6aa82eb1bf8a0645c4 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 11 Mar 2016 23:28:22 +0000 Subject: [PATCH 22/23] Comment `resolve_item_in_lexical_scope` --- src/librustc_resolve/lib.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index eefef015636ae..468c560b0bdbc 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1443,6 +1443,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { span) } + /// This function resolves `name` in `namespace` in the current lexical scope, returning + /// Success(binding) if `name` resolves to an item, or Failed(None) if `name` does not resolve + /// or resolves to a type parameter or local variable. + /// n.b. `resolve_identifier_in_local_ribs` also resolves names in the current lexical scope. + /// /// Invariant: This must only be called during main resolution, not during /// import resolution. fn resolve_item_in_lexical_scope(&mut self, @@ -1450,9 +1455,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { namespace: Namespace, record_used: bool) -> ResolveResult<&'a NameBinding<'a>> { - // Check the local set of ribs. + // Walk backwards up the ribs in scope. for i in (0 .. self.get_ribs(namespace).len()).rev() { if let Some(_) = self.get_ribs(namespace)[i].bindings.get(&name).cloned() { + // The name resolves to a type parameter or local variable, so return Failed(None). return Failed(None); } @@ -1462,6 +1468,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { namespace, true, record_used) { + // The name resolves to an item. return Success(binding); } // We can only see through anonymous modules From b308ed06846460150eb2a5f67c89ff4e63e7e665 Mon Sep 17 00:00:00 2001 From: srinivasreddy Date: Fri, 11 Mar 2016 00:05:53 +0530 Subject: [PATCH 23/23] Removed integer suffixes in libsyntax crate --- src/libsyntax/ast.rs | 6 +++--- src/libsyntax/print/pp.rs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index a8bea2da83349..f7621b0131ad4 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -927,7 +927,7 @@ pub enum ExprKind { Binary(BinOp, P, P), /// A unary operation (For example: `!x`, `*x`) Unary(UnOp, P), - /// A literal (For example: `1u8`, `"foo"`) + /// A literal (For example: `1`, `"foo"`) Lit(P), /// A cast (`foo as f64`) Cast(P, P), @@ -1016,7 +1016,7 @@ pub enum ExprKind { /// An array literal constructed from one repeated element. /// - /// For example, `[1u8; 5]`. The first expression is the element + /// For example, `[1; 5]`. The first expression is the element /// to be repeated; the second is the number of times to repeat it. Repeat(P, P), @@ -1288,7 +1288,7 @@ pub enum LitKind { Byte(u8), /// A character literal (`'a'`) Char(char), - /// An integer literal (`1u8`) + /// An integer literal (`1`) Int(u64, LitIntType), /// A float literal (`1f64` or `1E10f64`) Float(InternedString, FloatTy), diff --git a/src/libsyntax/print/pp.rs b/src/libsyntax/print/pp.rs index cbbd5289a5a2d..c1d922ea665b1 100644 --- a/src/libsyntax/print/pp.rs +++ b/src/libsyntax/print/pp.rs @@ -168,8 +168,8 @@ pub fn mk_printer<'a>(out: Box, linewidth: usize) -> Printer<'a> { let n: usize = 3 * linewidth; debug!("mk_printer {}", linewidth); let token = vec![Token::Eof; n]; - let size = vec![0_isize; n]; - let scan_stack = vec![0_usize; n]; + let size = vec![0; n]; + let scan_stack = vec![0; n]; Printer { out: out, buf_len: n,