diff options
| author | Dustin Speckhals <dustin1114@gmail.com> | 2017-10-29 13:27:06 -0400 |
|---|---|---|
| committer | Dustin Speckhals <dustin1114@gmail.com> | 2017-10-29 13:27:06 -0400 |
| commit | d284815f72f20c1edcf05066b376b45ed5390b4e (patch) | |
| tree | fb285b071a84ebe84d856eb004088f683e94eb82 | |
| parent | 1156455d4278b2d19910b0e198dfcc4560eadcb7 (diff) | |
| parent | 7d475a28dfa5399600c9b4121193fa57786ab88b (diff) | |
| download | rust-d284815f72f20c1edcf05066b376b45ed5390b4e.tar.gz rust-d284815f72f20c1edcf05066b376b45ed5390b4e.zip | |
Merge branch 'master' into rustfmt-update
100 files changed, 981 insertions, 212 deletions
diff --git a/src/bootstrap/cc_detect.rs b/src/bootstrap/cc_detect.rs index 6e3e3c92029..e531fdaf292 100644 --- a/src/bootstrap/cc_detect.rs +++ b/src/bootstrap/cc_detect.rs @@ -84,7 +84,7 @@ pub fn find(build: &mut Build) { if let Some(cc) = config.and_then(|c| c.cc.as_ref()) { cfg.compiler(cc); } else { - set_compiler(&mut cfg, "gcc", target, config, build); + set_compiler(&mut cfg, Language::C, target, config, build); } let compiler = cfg.get_compiler(); @@ -112,7 +112,7 @@ pub fn find(build: &mut Build) { if let Some(cxx) = config.and_then(|c| c.cxx.as_ref()) { cfg.compiler(cxx); } else { - set_compiler(&mut cfg, "g++", host, config, build); + set_compiler(&mut cfg, Language::CPlusPlus, host, config, build); } let compiler = cfg.get_compiler(); build.verbose(&format!("CXX_{} = {:?}", host, compiler.path())); @@ -121,7 +121,7 @@ pub fn find(build: &mut Build) { } fn set_compiler(cfg: &mut cc::Build, - gnu_compiler: &str, + compiler: Language, target: Interned<String>, config: Option<&Target>, build: &Build) { @@ -132,7 +132,7 @@ fn set_compiler(cfg: &mut cc::Build, t if t.contains("android") => { if let Some(ndk) = config.and_then(|c| c.ndk.as_ref()) { let target = target.replace("armv7", "arm"); - let compiler = format!("{}-{}", target, gnu_compiler); + let compiler = format!("{}-{}", target, compiler.clang()); cfg.compiler(ndk.join("bin").join(compiler)); } } @@ -141,6 +141,7 @@ fn set_compiler(cfg: &mut cc::Build, // which is a gcc version from ports, if this is the case. t if t.contains("openbsd") => { let c = cfg.get_compiler(); + let gnu_compiler = compiler.gcc(); if !c.path().ends_with(gnu_compiler) { return } @@ -183,3 +184,29 @@ fn set_compiler(cfg: &mut cc::Build, _ => {} } } + +/// The target programming language for a native compiler. +enum Language { + /// The compiler is targeting C. + C, + /// The compiler is targeting C++. + CPlusPlus, +} + +impl Language { + /// Obtains the name of a compiler in the GCC collection. + fn gcc(self) -> &'static str { + match self { + Language::C => "gcc", + Language::CPlusPlus => "g++", + } + } + + /// Obtains the name of a compiler in the clang suite. + fn clang(self) -> &'static str { + match self { + Language::C => "clang", + Language::CPlusPlus => "clang++", + } + } +} diff --git a/src/ci/docker/arm-android/Dockerfile b/src/ci/docker/arm-android/Dockerfile index 49d07d28d3c..f2773a720cf 100644 --- a/src/ci/docker/arm-android/Dockerfile +++ b/src/ci/docker/arm-android/Dockerfile @@ -5,21 +5,27 @@ RUN sh /scripts/android-base-apt-get.sh COPY scripts/android-ndk.sh /scripts/ RUN . /scripts/android-ndk.sh && \ - download_and_make_toolchain android-ndk-r13b-linux-x86_64.zip arm 9 + download_and_make_toolchain android-ndk-r15c-linux-x86_64.zip arm 14 +# Note: +# Do not upgrade to `openjdk-9-jre-headless`, as it will cause certificate error +# when installing the Android SDK (see PR #45193). This is unfortunate, but +# every search result suggested either disabling HTTPS or replacing JDK 9 by +# JDK 8 as the solution (e.g. https://stackoverflow.com/q/41421340). :| RUN dpkg --add-architecture i386 && \ apt-get update && \ apt-get install -y --no-install-recommends \ libgl1-mesa-glx \ libpulse0 \ libstdc++6:i386 \ - openjdk-9-jre-headless \ + openjdk-8-jre-headless \ tzdata COPY scripts/android-sdk.sh /scripts/ RUN . /scripts/android-sdk.sh && \ - download_and_create_avd tools_r25.2.5-linux.zip armeabi-v7a 18 + download_and_create_avd 4333796 armeabi-v7a 18 +ENV PATH=$PATH:/android/sdk/emulator ENV PATH=$PATH:/android/sdk/tools ENV PATH=$PATH:/android/sdk/platform-tools @@ -27,7 +33,7 @@ ENV TARGETS=arm-linux-androideabi ENV RUST_CONFIGURE_ARGS \ --target=$TARGETS \ - --arm-linux-androideabi-ndk=/android/ndk/arm-9 + --arm-linux-androideabi-ndk=/android/ndk/arm-14 ENV SCRIPT python2.7 ../x.py test --target $TARGETS diff --git a/src/ci/docker/disabled/dist-aarch64-android/Dockerfile b/src/ci/docker/disabled/dist-aarch64-android/Dockerfile index 20d823a3d73..ce5e8cfaf09 100644 --- a/src/ci/docker/disabled/dist-aarch64-android/Dockerfile +++ b/src/ci/docker/disabled/dist-aarch64-android/Dockerfile @@ -5,7 +5,7 @@ RUN sh /scripts/android-base-apt-get.sh COPY scripts/android-ndk.sh /scripts/ RUN . /scripts/android-ndk.sh && \ - download_and_make_toolchain android-ndk-r13b-linux-x86_64.zip arm64 21 + download_and_make_toolchain android-ndk-r15c-linux-x86_64.zip arm64 21 ENV PATH=$PATH:/android/ndk/arm64-21/bin diff --git a/src/ci/docker/disabled/dist-armv7-android/Dockerfile b/src/ci/docker/disabled/dist-armv7-android/Dockerfile index 3435d641a13..3177fa2147f 100644 --- a/src/ci/docker/disabled/dist-armv7-android/Dockerfile +++ b/src/ci/docker/disabled/dist-armv7-android/Dockerfile @@ -5,17 +5,17 @@ RUN sh /scripts/android-base-apt-get.sh COPY scripts/android-ndk.sh /scripts/ RUN . /scripts/android-ndk.sh && \ - download_ndk android-ndk-r13b-linux-x86_64.zip && \ - make_standalone_toolchain arm 9 && \ + download_ndk android-ndk-r15c-linux-x86_64.zip && \ + make_standalone_toolchain arm 14 && \ make_standalone_toolchain arm 21 && \ remove_ndk RUN chmod 777 /android/ndk && \ ln -s /android/ndk/arm-21 /android/ndk/arm -ENV PATH=$PATH:/android/ndk/arm-9/bin +ENV PATH=$PATH:/android/ndk/arm-14/bin -ENV DEP_Z_ROOT=/android/ndk/arm-9/sysroot/usr/ +ENV DEP_Z_ROOT=/android/ndk/arm-14/sysroot/usr/ ENV HOSTS=armv7-linux-androideabi @@ -27,18 +27,18 @@ ENV RUST_CONFIGURE_ARGS \ --enable-extended \ --enable-cargo-openssl-static -# We support api level 9, but api level 21 is required to build llvm. To +# We support api level 14, but api level 21 is required to build llvm. To # overcome this problem we use a ndk with api level 21 to build llvm and then -# switch to a ndk with api level 9 to complete the build. When the linker is +# switch to a ndk with api level 14 to complete the build. When the linker is # invoked there are missing symbols (like sigsetempty, not available with api -# level 9), the default linker behavior is to generate an error, to allow the +# level 14), the default linker behavior is to generate an error, to allow the # build to finish we use --warn-unresolved-symbols. Note that the missing # symbols does not affect std, only the compiler (llvm) and cargo (openssl). ENV SCRIPT \ python2.7 ../x.py build src/llvm --host $HOSTS --target $HOSTS && \ (export RUSTFLAGS="\"-C link-arg=-Wl,--warn-unresolved-symbols\""; \ rm /android/ndk/arm && \ - ln -s /android/ndk/arm-9 /android/ndk/arm && \ + ln -s /android/ndk/arm-14 /android/ndk/arm && \ python2.7 ../x.py dist --host $HOSTS --target $HOSTS) COPY scripts/sccache.sh /scripts/ diff --git a/src/ci/docker/disabled/dist-i686-android/Dockerfile b/src/ci/docker/disabled/dist-i686-android/Dockerfile index 4bb7053760f..ace9c4feb4f 100644 --- a/src/ci/docker/disabled/dist-i686-android/Dockerfile +++ b/src/ci/docker/disabled/dist-i686-android/Dockerfile @@ -5,17 +5,17 @@ RUN sh /scripts/android-base-apt-get.sh COPY scripts/android-ndk.sh /scripts/ RUN . /scripts/android-ndk.sh && \ - download_ndk android-ndk-r13b-linux-x86_64.zip && \ - make_standalone_toolchain x86 9 && \ + download_ndk android-ndk-r15c-linux-x86_64.zip && \ + make_standalone_toolchain x86 14 && \ make_standalone_toolchain x86 21 && \ remove_ndk RUN chmod 777 /android/ndk && \ ln -s /android/ndk/x86-21 /android/ndk/x86 -ENV PATH=$PATH:/android/ndk/x86-9/bin +ENV PATH=$PATH:/android/ndk/x86-14/bin -ENV DEP_Z_ROOT=/android/ndk/x86-9/sysroot/usr/ +ENV DEP_Z_ROOT=/android/ndk/x86-14/sysroot/usr/ ENV HOSTS=i686-linux-android @@ -27,18 +27,18 @@ ENV RUST_CONFIGURE_ARGS \ --enable-extended \ --enable-cargo-openssl-static -# We support api level 9, but api level 21 is required to build llvm. To +# We support api level 14, but api level 21 is required to build llvm. To # overcome this problem we use a ndk with api level 21 to build llvm and then -# switch to a ndk with api level 9 to complete the build. When the linker is +# switch to a ndk with api level 14 to complete the build. When the linker is # invoked there are missing symbols (like sigsetempty, not available with api -# level 9), the default linker behavior is to generate an error, to allow the +# level 14), the default linker behavior is to generate an error, to allow the # build to finish we use --warn-unresolved-symbols. Note that the missing # symbols does not affect std, only the compiler (llvm) and cargo (openssl). ENV SCRIPT \ python2.7 ../x.py build src/llvm --host $HOSTS --target $HOSTS && \ (export RUSTFLAGS="\"-C link-arg=-Wl,--warn-unresolved-symbols\""; \ rm /android/ndk/x86 && \ - ln -s /android/ndk/x86-9 /android/ndk/x86 && \ + ln -s /android/ndk/x86-14 /android/ndk/x86 && \ python2.7 ../x.py dist --host $HOSTS --target $HOSTS) COPY scripts/sccache.sh /scripts/ diff --git a/src/ci/docker/disabled/dist-x86_64-android/Dockerfile b/src/ci/docker/disabled/dist-x86_64-android/Dockerfile index 525b218417b..322d26f0adc 100644 --- a/src/ci/docker/disabled/dist-x86_64-android/Dockerfile +++ b/src/ci/docker/disabled/dist-x86_64-android/Dockerfile @@ -5,7 +5,7 @@ RUN sh /scripts/android-base-apt-get.sh COPY scripts/android-ndk.sh /scripts/ RUN . /scripts/android-ndk.sh && \ - download_and_make_toolchain android-ndk-r13b-linux-x86_64.zip x86_64 21 + download_and_make_toolchain android-ndk-r15c-linux-x86_64.zip x86_64 21 ENV PATH=$PATH:/android/ndk/x86_64-21/bin diff --git a/src/ci/docker/dist-android/Dockerfile b/src/ci/docker/dist-android/Dockerfile index a36f7fc1ac5..5d7545a3c2a 100644 --- a/src/ci/docker/dist-android/Dockerfile +++ b/src/ci/docker/dist-android/Dockerfile @@ -6,9 +6,9 @@ RUN sh /scripts/android-base-apt-get.sh # ndk COPY scripts/android-ndk.sh /scripts/ RUN . /scripts/android-ndk.sh && \ - download_ndk android-ndk-r13b-linux-x86_64.zip && \ - make_standalone_toolchain arm 9 && \ - make_standalone_toolchain x86 9 && \ + download_ndk android-ndk-r15c-linux-x86_64.zip && \ + make_standalone_toolchain arm 14 && \ + make_standalone_toolchain x86 14 && \ make_standalone_toolchain arm64 21 && \ make_standalone_toolchain x86_64 21 && \ remove_ndk @@ -23,9 +23,9 @@ ENV TARGETS=$TARGETS,x86_64-linux-android ENV RUST_CONFIGURE_ARGS \ --target=$TARGETS \ --enable-extended \ - --arm-linux-androideabi-ndk=/android/ndk/arm-9 \ - --armv7-linux-androideabi-ndk=/android/ndk/arm-9 \ - --i686-linux-android-ndk=/android/ndk/x86-9 \ + --arm-linux-androideabi-ndk=/android/ndk/arm-14 \ + --armv7-linux-androideabi-ndk=/android/ndk/arm-14 \ + --i686-linux-android-ndk=/android/ndk/x86-14 \ --aarch64-linux-android-ndk=/android/ndk/arm64-21 \ --x86_64-linux-android-ndk=/android/ndk/x86_64-21 diff --git a/src/ci/docker/scripts/android-sdk.sh b/src/ci/docker/scripts/android-sdk.sh index 3aa2b9d58d5..99c5776c2e8 100644 --- a/src/ci/docker/scripts/android-sdk.sh +++ b/src/ci/docker/scripts/android-sdk.sh @@ -10,40 +10,40 @@ set -ex -URL=https://dl.google.com/android/repository +export ANDROID_HOME=/android/sdk +PATH=$PATH:"${ANDROID_HOME}/tools/bin" download_sdk() { - mkdir -p /android/sdk - cd /android/sdk - curl -fO $URL/$1 - unzip -q $1 - rm -rf $1 + mkdir -p /android + curl -fo sdk.zip "https://dl.google.com/android/repository/sdk-tools-linux-$1.zip" + unzip -q sdk.zip -d "$ANDROID_HOME" + rm -f sdk.zip } download_sysimage() { - # See https://developer.android.com/studio/tools/help/android.html abi=$1 api=$2 - filter="platform-tools,android-$api" - filter="$filter,sys-img-$abi-android-$api" - - # Keep printing yes to accept the licenses - while true; do echo yes; sleep 10; done | \ - /android/sdk/tools/android update sdk -a --no-ui \ - --filter "$filter" --no-https + # See https://developer.android.com/studio/command-line/sdkmanager.html for + # usage of `sdkmanager`. + # + # The output from sdkmanager is so noisy that it will occupy all of the 4 MB + # log extremely quickly. Thus we must silence all output. + yes | sdkmanager --licenses > /dev/null + sdkmanager platform-tools emulator \ + "platforms;android-$api" \ + "system-images;android-$api;default;$abi" > /dev/null } create_avd() { - # See https://developer.android.com/studio/tools/help/android.html abi=$1 api=$2 - echo no | \ - /android/sdk/tools/android create avd \ - --name $abi-$api \ - --target android-$api \ - --abi $abi + # See https://developer.android.com/studio/command-line/avdmanager.html for + # usage of `avdmanager`. + echo no | avdmanager create avd \ + -n "$abi-$api" \ + -k "system-images;android-$api;default;$abi" } download_and_create_avd() { @@ -51,3 +51,15 @@ download_and_create_avd() { download_sysimage $2 $3 create_avd $2 $3 } + +# Usage: +# +# setup_android_sdk 4333796 armeabi-v7a 18 +# +# 4333796 => +# SDK tool version. +# Copy from https://developer.android.com/studio/index.html#command-tools +# armeabi-v7a => +# System image ABI +# 18 => +# Android API Level (18 = Android 4.3 = Jelly Bean MR2) diff --git a/src/doc/book b/src/doc/book -Subproject 808f482db94391fca1e04a9692b59e9eda8cfef +Subproject 7db393dae740d84775b73f403123c866e94e3a5 diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index 4e0c6479abf..64bcdc7920a 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -35,6 +35,7 @@ pub enum Def { Variant(DefId), Trait(DefId), TyAlias(DefId), + TyForeign(DefId), AssociatedTy(DefId), PrimTy(hir::PrimTy), TyParam(DefId), @@ -152,7 +153,7 @@ impl Def { Def::AssociatedTy(id) | Def::TyParam(id) | Def::Struct(id) | Def::StructCtor(id, ..) | Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) | Def::AssociatedConst(id) | Def::Macro(id, ..) | - Def::GlobalAsm(id) => { + Def::GlobalAsm(id) | Def::TyForeign(id) => { id } @@ -186,6 +187,7 @@ impl Def { Def::StructCtor(.., CtorKind::Fictive) => bug!("impossible struct constructor"), Def::Union(..) => "union", Def::Trait(..) => "trait", + Def::TyForeign(..) => "foreign type", Def::Method(..) => "method", Def::Const(..) => "constant", Def::AssociatedConst(..) => "associated constant", diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index d99d7cd897b..ae25924ab42 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -704,6 +704,7 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v } } ForeignItemStatic(ref typ, _) => visitor.visit_ty(typ), + ForeignItemType => (), } walk_list!(visitor, visit_attribute, &foreign_item.attrs); diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 184e6646558..3834852cac5 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1722,6 +1722,9 @@ impl<'a> LoweringContext<'a> { ForeignItemKind::Static(ref t, m) => { hir::ForeignItemStatic(this.lower_ty(t), m) } + ForeignItemKind::Ty => { + hir::ForeignItemType + } }, vis: this.lower_visibility(&i.vis, None), span: i.span, diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index fb3fc8a2da4..ca5ffe83048 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1912,6 +1912,8 @@ pub enum ForeignItem_ { /// A foreign static item (`static ext: u8`), with optional mutability /// (the boolean is true when mutable) ForeignItemStatic(P<Ty>, bool), + /// A foreign type + ForeignItemType, } impl ForeignItem_ { @@ -1919,6 +1921,7 @@ impl ForeignItem_ { match *self { ForeignItemFn(..) => "foreign function", ForeignItemStatic(..) => "foreign static item", + ForeignItemType => "foreign type", } } } diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index b4614873550..24a0b5fcea9 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -478,6 +478,13 @@ impl<'a> State<'a> { self.end()?; // end the head-ibox self.end() // end the outer cbox } + hir::ForeignItemType => { + self.head(&visibility_qualified(&item.vis, "type"))?; + self.print_name(item.name)?; + self.s.word(";")?; + self.end()?; // end the head-ibox + self.end() // end the outer cbox + } } } diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 994f0bd16b1..181b97aa7b5 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -977,7 +977,8 @@ impl_stable_hash_for!(struct hir::ForeignItem { impl_stable_hash_for!(enum hir::ForeignItem_ { ForeignItemFn(fn_decl, arg_names, generics), - ForeignItemStatic(ty, is_mutbl) + ForeignItemStatic(ty, is_mutbl), + ForeignItemType }); impl_stable_hash_for!(enum hir::Stmt_ { @@ -1086,6 +1087,7 @@ impl_stable_hash_for!(enum hir::def::Def { PrimTy(prim_ty), TyParam(def_id), SelfTy(trait_def_id, impl_def_id), + TyForeign(def_id), Fn(def_id), Const(def_id), Static(def_id, is_mutbl), diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 8a8dfbabbe1..48d3017f597 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -610,8 +610,7 @@ for ty::TypeVariants<'gcx> def_id.hash_stable(hcx, hasher); closure_substs.hash_stable(hcx, hasher); } - TyGenerator(def_id, closure_substs, interior) - => { + TyGenerator(def_id, closure_substs, interior) => { def_id.hash_stable(hcx, hasher); closure_substs.hash_stable(hcx, hasher); interior.hash_stable(hcx, hasher); @@ -630,6 +629,9 @@ for ty::TypeVariants<'gcx> TyParam(param_ty) => { param_ty.hash_stable(hcx, hasher); } + TyForeign(def_id) => { + def_id.hash_stable(hcx, hasher); + } TyInfer(..) => { bug!("ty::TypeVariants::hash_stable() - Unexpected variant {:?}.", *self) } diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index c274f8bda9f..41e7dffe54d 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -312,6 +312,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { ty::TyNever | ty::TyTuple(..) | ty::TyProjection(..) | + ty::TyForeign(..) | ty::TyParam(..) | ty::TyAnon(..) => { t.super_fold_with(self) diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index dc912f1c1b6..ee0e580920e 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -365,6 +365,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir::ForeignItemStatic(..) => { intravisit::walk_foreign_item(self, item); } + hir::ForeignItemType => { + intravisit::walk_foreign_item(self, item); + } } } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 4e4fc8b3118..b30d5e38488 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -18,8 +18,9 @@ use hir::def::Def; use hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, LOCAL_CRATE}; use ty::{self, TyCtxt}; use middle::privacy::AccessLevels; +use session::DiagnosticMessageId; use syntax::symbol::Symbol; -use syntax_pos::{Span, DUMMY_SP}; +use syntax_pos::{Span, MultiSpan, DUMMY_SP}; use syntax::ast; use syntax::ast::{NodeId, Attribute}; use syntax::feature_gate::{GateIssue, emit_feature_err, find_lang_feature_accepted_version}; @@ -597,8 +598,29 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { feature.as_str(), &r), None => format!("use of unstable library feature '{}'", &feature) }; - emit_feature_err(&self.sess.parse_sess, &feature.as_str(), span, - GateIssue::Library(Some(issue)), &msg); + + + let msp: MultiSpan = span.into(); + let cm = &self.sess.parse_sess.codemap(); + let span_key = msp.primary_span().and_then(|sp: Span| + if sp != DUMMY_SP { + let file = cm.lookup_char_pos(sp.lo()).file; + if file.name.starts_with("<") && file.name.ends_with(" macros>") { + None + } else { + Some(span) + } + } else { + None + } + ); + + let error_id = (DiagnosticMessageId::StabilityId(issue), span_key, msg.clone()); + let fresh = self.sess.one_time_diagnostics.borrow_mut().insert(error_id); + if fresh { + emit_feature_err(&self.sess.parse_sess, &feature.as_str(), span, + GateIssue::Library(Some(issue)), &msg); + } } Some(_) => { // Stable APIs are always ok to call and deprecated APIs are diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index c87881341da..be35cc8e4a1 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -75,10 +75,10 @@ pub struct Session { pub working_dir: (String, bool), pub lint_store: RefCell<lint::LintStore>, pub buffered_lints: RefCell<Option<lint::LintBuffer>>, - /// Set of (LintId, Option<Span>, message) tuples tracking lint + /// Set of (DiagnosticId, Option<Span>, message) tuples tracking /// (sub)diagnostics that have been set once, but should not be set again, - /// in order to avoid redundantly verbose output (Issue #24690). - pub one_time_diagnostics: RefCell<FxHashSet<(lint::LintId, Option<Span>, String)>>, + /// in order to avoid redundantly verbose output (Issue #24690, #44953). + pub one_time_diagnostics: RefCell<FxHashSet<(DiagnosticMessageId, Option<Span>, String)>>, pub plugin_llvm_passes: RefCell<Vec<String>>, pub plugin_attributes: RefCell<Vec<(String, AttributeType)>>, pub crate_types: RefCell<Vec<config::CrateType>>, @@ -164,6 +164,13 @@ enum DiagnosticBuilderMethod { // add more variants as needed to support one-time diagnostics } +/// Diagnostic message id - used in order to avoid emitting the same message more than once +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum DiagnosticMessageId { + LintId(lint::LintId), + StabilityId(u32) +} + impl Session { pub fn local_crate_disambiguator(&self) -> CrateDisambiguator { match *self.crate_disambiguator.borrow() { @@ -360,7 +367,7 @@ impl Session { do_method() }, _ => { - let lint_id = lint::LintId::of(lint); + let lint_id = DiagnosticMessageId::LintId(lint::LintId::of(lint)); let id_span_message = (lint_id, span, message.to_owned()); let fresh = self.one_time_diagnostics.borrow_mut().insert(id_span_message); if fresh { diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index dc5ce735324..10a32c26e74 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -304,6 +304,10 @@ fn ty_is_local_constructor(ty: Ty, infer_is_local: InferIsLocal)-> bool { def.did.is_local() } + ty::TyForeign(did) => { + did.is_local() + } + ty::TyDynamic(ref tt, ..) => { tt.principal().map_or(false, |p| p.def_id().is_local()) } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 030b7e4f646..e2b23c12cf1 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -255,6 +255,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { AdtKind::Enum => Some(17), }, ty::TyGenerator(..) => Some(18), + ty::TyForeign(..) => Some(19), ty::TyInfer(..) | ty::TyError => None } } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index cec79faff31..6c573acf07d 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1705,6 +1705,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // say nothing; a candidate may be added by // `assemble_candidates_from_object_ty`. } + ty::TyForeign(..) => { + // Since the contents of foreign types is unknown, + // we don't add any `..` impl. Default traits could + // still be provided by a manual implementation for + // this trait and type. + } ty::TyParam(..) | ty::TyProjection(..) => { // In these cases, we don't know what the actual @@ -2022,7 +2028,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { Where(ty::Binder(Vec::new())) } - ty::TyStr | ty::TySlice(_) | ty::TyDynamic(..) => Never, + ty::TyStr | ty::TySlice(_) | ty::TyDynamic(..) | ty::TyForeign(..) => Never, ty::TyTuple(tys, _) => { Where(ty::Binder(tys.last().into_iter().cloned().collect())) @@ -2066,7 +2072,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { Where(ty::Binder(Vec::new())) } - ty::TyDynamic(..) | ty::TyStr | ty::TySlice(..) | ty::TyGenerator(..) | + ty::TyDynamic(..) | ty::TyStr | ty::TySlice(..) | + ty::TyGenerator(..) | ty::TyForeign(..) | ty::TyRef(_, ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => { Never } @@ -2148,6 +2155,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::TyDynamic(..) | ty::TyParam(..) | + ty::TyForeign(..) | ty::TyProjection(..) | ty::TyInfer(ty::TyVar(_)) | ty::TyInfer(ty::FreshTy(_)) | diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index ebd9fa93236..6ab81a41d68 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1610,7 +1610,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { pub fn print_debug_stats(self) { sty_debug_print!( self, - TyAdt, TyArray, TySlice, TyRawPtr, TyRef, TyFnDef, TyFnPtr, TyGenerator, + TyAdt, TyArray, TySlice, TyRawPtr, TyRef, TyFnDef, TyFnPtr, TyGenerator, TyForeign, TyDynamic, TyClosure, TyTuple, TyParam, TyInfer, TyProjection, TyAnon); println!("Substs interner: #{}", self.interners.substs.borrow().len()); @@ -1861,6 +1861,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.mk_ty(TyAdt(def, substs)) } + pub fn mk_foreign(self, def_id: DefId) -> Ty<'tcx> { + self.mk_ty(TyForeign(def_id)) + } + pub fn mk_box(self, ty: Ty<'tcx>) -> Ty<'tcx> { let def_id = self.require_lang_item(lang_items::OwnedBoxLangItem); let adt_def = self.adt_def(def_id); diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 52a8389bd8f..5cfa72c0712 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -182,6 +182,7 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { ty::TyTuple(ref tys, _) if tys.is_empty() => self.to_string(), ty::TyAdt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)), + ty::TyForeign(def_id) => format!("extern type `{}`", tcx.item_path_str(def_id)), ty::TyArray(_, n) => { if let ConstVal::Integral(ConstInt::Usize(n)) = n.val { format!("array of {} elements", n) diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs index 490bfe78a9a..138f6af77c6 100644 --- a/src/librustc/ty/fast_reject.rs +++ b/src/librustc/ty/fast_reject.rs @@ -49,6 +49,7 @@ pub enum SimplifiedTypeGen<D> AnonSimplifiedType(D), FunctionSimplifiedType(usize), ParameterSimplifiedType, + ForeignSimplifiedType(DefId), } /// Tries to simplify a type by dropping type parameters, deref'ing away any reference types, etc. @@ -113,6 +114,9 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, ty::TyAnon(def_id, _) => { Some(AnonSimplifiedType(def_id)) } + ty::TyForeign(def_id) => { + Some(ForeignSimplifiedType(def_id)) + } ty::TyInfer(_) | ty::TyError => None, } } @@ -140,6 +144,7 @@ impl<D: Copy + Debug + Ord + Eq + Hash> SimplifiedTypeGen<D> { AnonSimplifiedType(d) => AnonSimplifiedType(map(d)), FunctionSimplifiedType(n) => FunctionSimplifiedType(n), ParameterSimplifiedType => ParameterSimplifiedType, + ForeignSimplifiedType(d) => ForeignSimplifiedType(d), } } } @@ -172,6 +177,7 @@ impl<'gcx, D> HashStable<StableHashingContext<'gcx>> for SimplifiedTypeGen<D> GeneratorSimplifiedType(d) => d.hash_stable(hcx, hasher), AnonSimplifiedType(d) => d.hash_stable(hcx, hasher), FunctionSimplifiedType(n) => n.hash_stable(hcx, hasher), + ForeignSimplifiedType(d) => d.hash_stable(hcx, hasher), } } } diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 9ece719c764..63c646dbd23 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -63,7 +63,8 @@ impl FlagComputation { &ty::TyFloat(_) | &ty::TyUint(_) | &ty::TyNever | - &ty::TyStr => { + &ty::TyStr | + &ty::TyForeign(..) => { } // You might think that we could just return TyError for diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index a8ccb3e269f..98c55331f8a 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -281,6 +281,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } + ty::TyForeign(did) => self.push_item_path(buffer, did), + ty::TyBool | ty::TyChar | ty::TyInt(_) | @@ -344,8 +346,9 @@ pub fn characteristic_def_id_of_type(ty: Ty) -> Option<DefId> { .next(), ty::TyFnDef(def_id, _) | - ty::TyClosure(def_id, _) => Some(def_id), - ty::TyGenerator(def_id, _, _) => Some(def_id), + ty::TyClosure(def_id, _) | + ty::TyGenerator(def_id, _, _) | + ty::TyForeign(def_id) => Some(def_id), ty::TyBool | ty::TyChar | diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 1709f9ed2df..491fa2a240c 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1141,14 +1141,15 @@ impl<'a, 'tcx> Layout { Ok(Scalar { value: Pointer, non_zero: non_zero }) } else { let unsized_part = tcx.struct_tail(pointee); - let meta = match unsized_part.sty { - ty::TySlice(_) | ty::TyStr => { - Int(dl.ptr_sized_integer()) - } - ty::TyDynamic(..) => Pointer, - _ => return Err(LayoutError::Unknown(unsized_part)) - }; - Ok(FatPointer { metadata: meta, non_zero: non_zero }) + match unsized_part.sty { + ty::TySlice(_) | ty::TyStr => Ok(FatPointer { + metadata: Int(dl.ptr_sized_integer()), + non_zero: non_zero + }), + ty::TyDynamic(..) => Ok(FatPointer { metadata: Pointer, non_zero: non_zero }), + ty::TyForeign(..) => Ok(Scalar { value: Pointer, non_zero: non_zero }), + _ => Err(LayoutError::Unknown(unsized_part)), + } } }; @@ -1239,7 +1240,7 @@ impl<'a, 'tcx> Layout { non_zero: false } } - ty::TyDynamic(..) => { + ty::TyDynamic(..) | ty::TyForeign(..) => { let mut unit = Struct::new(dl, &vec![], &ReprOptions::default(), StructKind::AlwaysSizedUnivariant, ty)?; unit.sized = false; @@ -2252,7 +2253,8 @@ impl<'a, 'tcx> TyLayout<'tcx> { ty::TyFnPtr(_) | ty::TyNever | ty::TyFnDef(..) | - ty::TyDynamic(..) => { + ty::TyDynamic(..) | + ty::TyForeign(..) => { bug!("TyLayout::field_type({:?}): not applicable", self) } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 9b239a35f90..b3f2886cdf9 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1784,7 +1784,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { vec![] } - TyStr | TyDynamic(..) | TySlice(_) | TyError => { + TyStr | TyDynamic(..) | TySlice(_) | TyForeign(..) | TyError => { // these are never sized - return the target type vec![ty] } diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs index 5e1dc485d42..707137649d7 100644 --- a/src/librustc/ty/outlives.rs +++ b/src/librustc/ty/outlives.rs @@ -142,6 +142,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty::TyNever | // ... ty::TyAdt(..) | // OutlivesNominalType ty::TyAnon(..) | // OutlivesNominalType (ish) + ty::TyForeign(..) | // OutlivesNominalType ty::TyStr | // OutlivesScalar (ish) ty::TyArray(..) | // ... ty::TySlice(..) | // ... diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 309880ba063..376cdc462e8 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -381,6 +381,12 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, Ok(tcx.mk_adt(a_def, substs)) } + (&ty::TyForeign(a_id), &ty::TyForeign(b_id)) + if a_id == b_id => + { + Ok(tcx.mk_foreign(a_id)) + } + (&ty::TyDynamic(ref a_obj, ref a_region), &ty::TyDynamic(ref b_obj, ref b_region)) => { let region_bound = relation.with_cause(Cause::ExistentialRegionBound, |relation| { diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 54d55748c8e..5f1448cd1f1 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -676,7 +676,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty::TyAnon(did, substs) => ty::TyAnon(did, substs.fold_with(folder)), ty::TyBool | ty::TyChar | ty::TyStr | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | ty::TyError | ty::TyInfer(_) | - ty::TyParam(..) | ty::TyNever => return self + ty::TyParam(..) | ty::TyNever | ty::TyForeign(..) => return self }; if self.sty == sty { @@ -710,7 +710,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty::TyAnon(_, ref substs) => substs.visit_with(visitor), ty::TyBool | ty::TyChar | ty::TyStr | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | ty::TyError | ty::TyInfer(_) | - ty::TyParam(..) | ty::TyNever => false, + ty::TyParam(..) | ty::TyNever | ty::TyForeign(..) => false, } } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 064627c21bf..d0ac7d0183a 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -104,6 +104,8 @@ pub enum TypeVariants<'tcx> { /// definition and not a concrete use of it. TyAdt(&'tcx AdtDef, &'tcx Substs<'tcx>), + TyForeign(DefId), + /// The pointee of a string slice. Written as `str`. TyStr, @@ -1117,13 +1119,6 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } - pub fn is_structural(&self) -> bool { - match self.sty { - TyAdt(..) | TyTuple(..) | TyArray(..) | TyClosure(..) => true, - _ => self.is_slice() | self.is_trait(), - } - } - #[inline] pub fn is_simd(&self) -> bool { match self.sty { @@ -1347,6 +1342,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { match self.sty { TyDynamic(ref tt, ..) => tt.principal().map(|p| p.def_id()), TyAdt(def, _) => Some(def.did), + TyForeign(did) => Some(did), TyClosure(id, _) => Some(id), _ => None, } @@ -1396,6 +1392,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { TyRawPtr(_) | TyNever | TyTuple(..) | + TyForeign(..) | TyParam(_) | TyInfer(_) | TyError => { diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index c8037ce081a..39842a543b5 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -553,7 +553,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let result = match ty.sty { ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | - ty::TyFloat(_) | ty::TyStr | ty::TyNever | + ty::TyFloat(_) | ty::TyStr | ty::TyNever | ty::TyForeign(..) | ty::TyRawPtr(..) | ty::TyRef(..) | ty::TyFnDef(..) | ty::TyFnPtr(_) => { // these types never have a destructor Ok(ty::DtorckConstraint::empty()) @@ -714,6 +714,7 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W> TyAnon(def_id, _) | TyFnDef(def_id, _) => self.def_id(def_id), TyAdt(d, _) => self.def_id(d.did), + TyForeign(def_id) => self.def_id(def_id), TyFnPtr(f) => { self.hash(f.unsafety()); self.hash(f.abi()); @@ -1109,6 +1110,9 @@ fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar | ty::TyRawPtr(_) | ty::TyRef(..) | ty::TyStr => false, + // Foreign types can never have destructors + ty::TyForeign(..) => false, + // Issue #22536: We first query type_moves_by_default. It sees a // normalized version of the type, and therefore will definitely // know whether the type implements Copy (and thus needs no diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index df07844cceb..448ad4cf675 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -82,7 +82,8 @@ pub fn walk_shallow<'tcx>(ty: Ty<'tcx>) -> AccIntoIter<TypeWalkerArray<'tcx>> { fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) { match parent_ty.sty { ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | - ty::TyStr | ty::TyInfer(_) | ty::TyParam(_) | ty::TyNever | ty::TyError => { + ty::TyStr | ty::TyInfer(_) | ty::TyParam(_) | ty::TyNever | ty::TyError | + ty::TyForeign(..) => { } ty::TyArray(ty, len) => { push_const(stack, len); diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 41e27fca3f3..c631e2c4db5 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -284,7 +284,8 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { ty::TyError | ty::TyStr | ty::TyNever | - ty::TyParam(_) => { + ty::TyParam(_) | + ty::TyForeign(..) => { // WfScalar, WfParameter, etc } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 0eb2c19fe44..acb929981fb 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -17,7 +17,7 @@ use ty::{BrAnon, BrEnv, BrFresh, BrNamed}; use ty::{TyBool, TyChar, TyAdt}; use ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyFnDef, TyFnPtr}; use ty::{TyParam, TyRawPtr, TyRef, TyNever, TyTuple}; -use ty::{TyClosure, TyGenerator, TyProjection, TyAnon}; +use ty::{TyClosure, TyGenerator, TyForeign, TyProjection, TyAnon}; use ty::{TyDynamic, TyInt, TyUint, TyInfer}; use ty::{self, Ty, TyCtxt, TypeFoldable}; use util::nodemap::FxHashSet; @@ -1012,6 +1012,7 @@ define_print! { Ok(()) } } + TyForeign(def_id) => parameterized(f, subst::Substs::empty(), def_id, &[]), TyProjection(ref data) => data.print(f, cx), TyAnon(def_id, substs) => { ty::tls::with(|tcx| { diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 38461b0b364..8f08987505b 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -621,6 +621,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { FfiSafe } + ty::TyForeign(..) => FfiSafe, + ty::TyParam(..) | ty::TyInfer(..) | ty::TyError | @@ -723,6 +725,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypes { hir::ForeignItemStatic(ref ty, _) => { vis.check_foreign_static(ni.id, ty.span); } + hir::ForeignItemType => () } } } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 65cf15e5a0e..909e01376b9 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -449,6 +449,7 @@ impl<'tcx> EntryKind<'tcx> { EntryKind::Enum(..) => Def::Enum(did), EntryKind::MacroDef(_) => Def::Macro(did, MacroKind::Bang), EntryKind::GlobalAsm => Def::GlobalAsm(did), + EntryKind::ForeignType => Def::TyForeign(did), EntryKind::ForeignMod | EntryKind::Impl(_) | diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 6b49be3e121..abe2b6d0c1b 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1419,6 +1419,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { } hir::ForeignItemStatic(_, true) => EntryKind::ForeignMutStatic, hir::ForeignItemStatic(_, false) => EntryKind::ForeignImmStatic, + hir::ForeignItemType => EntryKind::ForeignType, }; Entry { diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 43dbce5288a..3c3162bcb51 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -292,6 +292,7 @@ pub enum EntryKind<'tcx> { ForeignImmStatic, ForeignMutStatic, ForeignMod, + ForeignType, GlobalAsm, Type, Enum(ReprOptions), @@ -325,6 +326,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for EntryKind<'gcx> { EntryKind::ForeignMutStatic | EntryKind::ForeignMod | EntryKind::GlobalAsm | + EntryKind::ForeignType | EntryKind::Field | EntryKind::Type => { // Nothing else to hash here. diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 14e33378969..e44f3f39824 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -288,7 +288,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { err.emit(); }); } - ForeignItemKind::Static(..) => {} + ForeignItemKind::Static(..) | ForeignItemKind::Ty => {} } visit::walk_foreign_item(self, fi) diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 8abf7d3d09c..3beba03ee14 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -85,6 +85,7 @@ impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> { fn item_ty_level(&self, item_def_id: DefId) -> Option<AccessLevel> { let ty_def_id = match self.tcx.type_of(item_def_id).sty { ty::TyAdt(adt, _) => adt.did, + ty::TyForeign(did) => did, ty::TyDynamic(ref obj, ..) if obj.principal().is_some() => obj.principal().unwrap().def_id(), ty::TyProjection(ref proj) => proj.trait_ref(self.tcx).def_id, @@ -444,6 +445,7 @@ impl<'b, 'a, 'tcx> TypeVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'b fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { let ty_def_id = match ty.sty { ty::TyAdt(adt, _) => Some(adt.did), + ty::TyForeign(did) => Some(did), ty::TyDynamic(ref obj, ..) => obj.principal().map(|p| p.def_id()), ty::TyProjection(ref proj) => Some(proj.item_def_id), ty::TyFnDef(def_id, ..) | @@ -800,7 +802,9 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { impl<'a, 'tcx> TypeVisitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { match ty.sty { - ty::TyAdt(&ty::AdtDef { did: def_id, .. }, ..) | ty::TyFnDef(def_id, ..) => { + ty::TyAdt(&ty::AdtDef { did: def_id, .. }, ..) | + ty::TyFnDef(def_id, ..) | + ty::TyForeign(def_id) => { if !self.item_is_accessible(def_id) { let msg = format!("type `{}` is private", ty); self.tcx.sess.span_err(self.span, &msg); @@ -1329,6 +1333,7 @@ impl<'a, 'tcx: 'a> TypeVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<' fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { let ty_def_id = match ty.sty { ty::TyAdt(adt, _) => Some(adt.did), + ty::TyForeign(did) => Some(did), ty::TyDynamic(ref obj, ..) => obj.principal().map(|p| p.def_id()), ty::TyProjection(ref proj) => { if self.required_visibility == ty::Visibility::Invisible { @@ -1349,8 +1354,13 @@ impl<'a, 'tcx: 'a> TypeVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<' if let Some(def_id) = ty_def_id { // Non-local means public (private items can't leave their crate, modulo bugs) if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) { - let item = self.tcx.hir.expect_item(node_id); - let vis = ty::Visibility::from_hir(&item.vis, node_id, self.tcx); + let vis = match self.tcx.hir.find(node_id) { + Some(hir::map::NodeItem(item)) => &item.vis, + Some(hir::map::NodeForeignItem(item)) => &item.vis, + _ => bug!("expected item of foreign item"), + }; + + let vis = ty::Visibility::from_hir(vis, node_id, self.tcx); if !vis.is_at_least(self.min_visibility, self.tcx) { self.min_visibility = vis; diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 7b1a602d849..880b370c7f6 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -419,17 +419,20 @@ impl<'a> Resolver<'a> { /// Constructs the reduced graph for one foreign item. fn build_reduced_graph_for_foreign_item(&mut self, item: &ForeignItem, expansion: Mark) { - let def = match item.node { + let (def, ns) = match item.node { ForeignItemKind::Fn(..) => { - Def::Fn(self.definitions.local_def_id(item.id)) + (Def::Fn(self.definitions.local_def_id(item.id)), ValueNS) } ForeignItemKind::Static(_, m) => { - Def::Static(self.definitions.local_def_id(item.id), m) + (Def::Static(self.definitions.local_def_id(item.id), m), ValueNS) + } + ForeignItemKind::Ty => { + (Def::TyForeign(self.definitions.local_def_id(item.id)), TypeNS) } }; let parent = self.current_module; let vis = self.resolve_visibility(&item.vis); - self.define(parent, item.ident, ValueNS, (def, vis, item.span, expansion)); + self.define(parent, item.ident, ns, (def, vis, item.span, expansion)); } fn build_reduced_graph_for_block(&mut self, block: &Block, expansion: Mark) { @@ -462,7 +465,7 @@ impl<'a> Resolver<'a> { span); self.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, expansion)); } - Def::Variant(..) | Def::TyAlias(..) => { + Def::Variant(..) | Def::TyAlias(..) | Def::TyForeign(..) => { self.define(parent, ident, TypeNS, (def, vis, DUMMY_SP, expansion)); } Def::Fn(..) | Def::Static(..) | Def::Const(..) | Def::VariantCtor(..) => { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 8d8e6105e47..83eeaf551c5 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -468,7 +468,8 @@ impl<'a> PathSource<'a> { PathSource::Type => match def { Def::Struct(..) | Def::Union(..) | Def::Enum(..) | Def::Trait(..) | Def::TyAlias(..) | Def::AssociatedTy(..) | - Def::PrimTy(..) | Def::TyParam(..) | Def::SelfTy(..) => true, + Def::PrimTy(..) | Def::TyParam(..) | Def::SelfTy(..) | + Def::TyForeign(..) => true, _ => false, }, PathSource::Trait => match def { @@ -707,6 +708,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { HasTypeParameters(generics, ItemRibKind) } ForeignItemKind::Static(..) => NoTypeParameters, + ForeignItemKind::Ty => NoTypeParameters, }; self.with_type_parameter_rib(type_parameters, |this| { visit::walk_foreign_item(this, foreign_item); diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index ca44a088e23..4eac4398c18 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -263,6 +263,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { HirDef::Union(..) | HirDef::Enum(..) | HirDef::TyAlias(..) | + HirDef::TyForeign(..) | HirDef::Trait(_) => { let span = self.span_from_span(sub_span.expect("No span found for type ref")); self.dumper.dump_ref(Ref { @@ -1539,6 +1540,12 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc self.visit_ty(ty); } + ast::ForeignItemKind::Ty => { + if let Some(var_data) = self.save_ctxt.get_extern_item_data(item) { + down_cast_data!(var_data, DefData, item.span); + self.dumper.dump_def(item.vis == ast::Visibility::Public, var_data); + } + } } } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 1c6007966af..cf2cad1b38c 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -173,6 +173,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { attributes: lower_attributes(item.attrs.clone(), self), })) } + // FIXME(plietar): needs a new DefKind in rls-data + ast::ForeignItemKind::Ty => None, } } @@ -642,6 +644,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { HirDef::Union(def_id) | HirDef::Enum(def_id) | HirDef::TyAlias(def_id) | + HirDef::TyForeign(def_id) | HirDef::AssociatedTy(def_id) | HirDef::Trait(def_id) | HirDef::TyParam(def_id) => { diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index 88f574d513b..b0844d1b824 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -808,6 +808,23 @@ impl Sig for ast::ForeignItem { Ok(extend_sig(ty_sig, text, defs, vec![])) } + ast::ForeignItemKind::Ty => { + let mut text = "type ".to_owned(); + let name = self.ident.to_string(); + let defs = vec![SigElement { + id: id_from_node_id(self.id, scx), + start: offset + text.len(), + end: offset + text.len() + name.len(), + }]; + text.push_str(&name); + text.push(';'); + + Ok(Signature { + text: text, + defs: defs, + refs: vec![], + }) + } } } } diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 6fd24c1786c..9df057c77a9 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -32,6 +32,7 @@ use rustc::session::Session; use rustc::ty::layout::{LayoutCx, LayoutError, LayoutTyper, TyLayout}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::util::nodemap::FxHashMap; +use rustc_trans_utils; use std::ffi::{CStr, CString}; use std::cell::{Cell, RefCell}; @@ -301,6 +302,10 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { common::type_is_freeze(self.tcx, ty) } + pub fn type_has_metadata(&self, ty: Ty<'tcx>) -> bool { + rustc_trans_utils::common::type_has_metadata(self.tcx, ty) + } + pub fn tcx(&self) -> TyCtxt<'b, 'tcx, 'tcx> { self.tcx } diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 3bde78e2c6a..4f07af9071d 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -543,6 +543,11 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, trait_pointer_metadata(cx, t, None, unique_type_id), false) } + ty::TyForeign(..) => { + MetadataCreationResult::new( + foreign_type_metadata(cx, t, unique_type_id), + false) + } ty::TyRawPtr(ty::TypeAndMut{ty, ..}) | ty::TyRef(_, ty::TypeAndMut{ty, ..}) => { match ptr_metadata(ty) { @@ -752,6 +757,17 @@ fn basic_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, return ty_metadata; } +fn foreign_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, + t: Ty<'tcx>, + unique_type_id: UniqueTypeId) -> DIType { + debug!("foreign_type_metadata: {:?}", t); + + let llvm_type = type_of::type_of(cx, t); + + let name = compute_debuginfo_type_name(cx, t, false); + create_struct_stub(cx, llvm_type, &name, unique_type_id, NO_SCOPE_METADATA) +} + fn pointer_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, pointer_type: Ty<'tcx>, pointee_type_metadata: DIType) diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs index 7bf9d39ea2f..85467f5bfbd 100644 --- a/src/librustc_trans/debuginfo/type_names.rs +++ b/src/librustc_trans/debuginfo/type_names.rs @@ -48,6 +48,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty::TyInt(int_ty) => output.push_str(int_ty.ty_to_string()), ty::TyUint(uint_ty) => output.push_str(uint_ty.ty_to_string()), ty::TyFloat(float_ty) => output.push_str(float_ty.ty_to_string()), + ty::TyForeign(def_id) => push_item_name(cx, def_id, qualified, output), ty::TyAdt(def, substs) => { push_item_name(cx, def.did, qualified, output); push_type_params(cx, substs, output); diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index f78d80a197c..e8023917568 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -139,13 +139,15 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, } "size_of_val" => { let tp_ty = substs.type_at(0); - if !bcx.ccx.shared().type_is_sized(tp_ty) { + if bcx.ccx.shared().type_is_sized(tp_ty) { + let lltp_ty = type_of::type_of(ccx, tp_ty); + C_usize(ccx, machine::llsize_of_alloc(ccx, lltp_ty)) + } else if bcx.ccx.shared().type_has_metadata(tp_ty) { let (llsize, _) = glue::size_and_align_of_dst(bcx, tp_ty, llargs[1]); llsize } else { - let lltp_ty = type_of::type_of(ccx, tp_ty); - C_usize(ccx, machine::llsize_of_alloc(ccx, lltp_ty)) + C_usize(ccx, 0u64) } } "min_align_of" => { @@ -154,12 +156,14 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, } "min_align_of_val" => { let tp_ty = substs.type_at(0); - if !bcx.ccx.shared().type_is_sized(tp_ty) { + if bcx.ccx.shared().type_is_sized(tp_ty) { + C_usize(ccx, ccx.align_of(tp_ty) as u64) + } else if bcx.ccx.shared().type_has_metadata(tp_ty) { let (_, llalign) = glue::size_and_align_of_dst(bcx, tp_ty, llargs[1]); llalign } else { - C_usize(ccx, ccx.align_of(tp_ty) as u64) + C_usize(ccx, 1u64) } } "pref_align_of" => { diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 1b8e68f691a..cea7b9585d8 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -428,11 +428,11 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { .projection_ty(tcx, &projection.elem); let base = tr_base.to_const(span); let projected_ty = self.monomorphize(&projected_ty).to_ty(tcx); - let is_sized = self.ccx.shared().type_is_sized(projected_ty); + let has_metadata = self.ccx.shared().type_has_metadata(projected_ty); let (projected, llextra) = match projection.elem { mir::ProjectionElem::Deref => { - let (base, extra) = if is_sized { + let (base, extra) = if !has_metadata { (base.llval, ptr::null_mut()) } else { base.get_fat_ptr() @@ -463,7 +463,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { mir::ProjectionElem::Field(ref field, _) => { let llprojected = adt::const_get_field(self.ccx, tr_base.ty, base.llval, field.index()); - let llextra = if is_sized { + let llextra = if !has_metadata { ptr::null_mut() } else { tr_base.llextra diff --git a/src/librustc_trans/mir/lvalue.rs b/src/librustc_trans/mir/lvalue.rs index 6799e52904d..d939acaccd9 100644 --- a/src/librustc_trans/mir/lvalue.rs +++ b/src/librustc_trans/mir/lvalue.rs @@ -147,15 +147,16 @@ impl<'a, 'tcx> LvalueRef<'tcx> { // * Packed struct - There is no alignment padding // * Field is sized - pointer is properly aligned already if st.offsets[ix] == layout::Size::from_bytes(0) || st.packed || - bcx.ccx.shared().type_is_sized(fty) { - return (bcx.struct_gep( - ptr_val, adt::struct_llfields_index(st, ix)), alignment); - } + bcx.ccx.shared().type_is_sized(fty) + { + return (bcx.struct_gep( + ptr_val, adt::struct_llfields_index(st, ix)), alignment); + } - // If the type of the last field is [T] or str, then we don't need to do + // If the type of the last field is [T], str or a foreign type, then we don't need to do // any adjusments match fty.sty { - ty::TySlice(..) | ty::TyStr => { + ty::TySlice(..) | ty::TyStr | ty::TyForeign(..) => { return (bcx.struct_gep( ptr_val, adt::struct_llfields_index(st, ix)), alignment); } @@ -328,7 +329,9 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let ((llprojected, align), llextra) = match projection.elem { mir::ProjectionElem::Deref => bug!(), mir::ProjectionElem::Field(ref field, _) => { - let llextra = if self.ccx.shared().type_is_sized(projected_ty.to_ty(tcx)) { + let has_metadata = self.ccx.shared() + .type_has_metadata(projected_ty.to_ty(tcx)); + let llextra = if !has_metadata { ptr::null_mut() } else { tr_base.llextra @@ -415,3 +418,4 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { self.monomorphize(&lvalue_ty.to_ty(tcx)) } } + diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 822431eba42..777b86387e8 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -364,7 +364,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { // Note: lvalues are indirect, so storing the `llval` into the // destination effectively creates a reference. - let operand = if bcx.ccx.shared().type_is_sized(ty) { + let operand = if !bcx.ccx.shared().type_has_metadata(ty) { OperandRef { val: OperandValue::Immediate(tr_lvalue.llval), ty: ref_ty, diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index db1af8cdefb..fb68be293a7 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -230,4 +230,3 @@ fn predefine_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ccx.instances().borrow_mut().insert(instance, lldecl); } - diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index 992c74b9020..cac09a81361 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -22,7 +22,7 @@ use syntax::ast; pub fn fat_ptr_base_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type { match ty.sty { ty::TyRef(_, ty::TypeAndMut { ty: t, .. }) | - ty::TyRawPtr(ty::TypeAndMut { ty: t, .. }) if !ccx.shared().type_is_sized(t) => { + ty::TyRawPtr(ty::TypeAndMut { ty: t, .. }) if ccx.shared().type_has_metadata(t) => { in_memory_type_of(ccx, t).ptr_to() } ty::TyAdt(def, _) if def.is_box() => { @@ -62,7 +62,7 @@ pub fn immediate_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> /// is too large for it to be placed in SSA value (by our rules). /// For the raw type without far pointer indirection, see `in_memory_type_of`. pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type { - let ty = if !cx.shared().type_is_sized(ty) { + let ty = if cx.shared().type_has_metadata(ty) { cx.tcx().mk_imm_ptr(ty) } else { ty @@ -106,7 +106,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> } let ptr_ty = |ty: Ty<'tcx>| { - if !cx.shared().type_is_sized(ty) { + if cx.shared().type_has_metadata(ty) { if let ty::TyStr = ty.sty { // This means we get a nicer name in the output (str is always // unsized). @@ -158,7 +158,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> // fat pointers is of the right type (e.g. for array accesses), even // when taking the address of an unsized field in a struct. ty::TySlice(ty) => in_memory_type_of(cx, ty), - ty::TyStr | ty::TyDynamic(..) => Type::i8(cx), + ty::TyStr | ty::TyDynamic(..) | ty::TyForeign(..) => Type::i8(cx), ty::TyFnDef(..) => Type::nil(cx), ty::TyFnPtr(sig) => { diff --git a/src/librustc_trans_utils/collector.rs b/src/librustc_trans_utils/collector.rs index c87d86262ef..cf9b80e5ed4 100644 --- a/src/librustc_trans_utils/collector.rs +++ b/src/librustc_trans_utils/collector.rs @@ -203,7 +203,7 @@ use rustc::ty::adjustment::CustomCoerceUnsized; use rustc::mir::{self, Location}; use rustc::mir::visit::Visitor as MirVisitor; -use common::{def_ty, instance_ty, type_is_sized}; +use common::{def_ty, instance_ty, type_has_metadata}; use monomorphize::{self, Instance}; use rustc::util::nodemap::{FxHashSet, FxHashMap, DefIdMap}; @@ -782,7 +782,7 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, target_ty: Ty<'tcx>) -> (Ty<'tcx>, Ty<'tcx>) { let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| { - if !type_is_sized(tcx, inner_source) { + if type_has_metadata(tcx, inner_source) { (inner_source, inner_target) } else { tcx.struct_lockstep_tails(inner_source, inner_target) diff --git a/src/librustc_trans_utils/common.rs b/src/librustc_trans_utils/common.rs index 634e37220e2..ec9c5b1119b 100644 --- a/src/librustc_trans_utils/common.rs +++ b/src/librustc_trans_utils/common.rs @@ -25,6 +25,19 @@ pub fn type_is_sized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> boo ty.is_sized(tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP) } +pub fn type_has_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool { + if type_is_sized(tcx, ty) { + return false; + } + + let tail = tcx.struct_tail(ty); + match tail.sty { + ty::TyForeign(..) => false, + ty::TyStr | ty::TySlice(..) | ty::TyDynamic(..) => true, + _ => bug!("unexpected unsized tail: {:?}", tail.sty), + } +} + pub fn requests_inline<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: &ty::Instance<'tcx> diff --git a/src/librustc_trans_utils/lib.rs b/src/librustc_trans_utils/lib.rs index b468c510c09..6a341a1e7d3 100644 --- a/src/librustc_trans_utils/lib.rs +++ b/src/librustc_trans_utils/lib.rs @@ -48,7 +48,7 @@ use rustc::util::nodemap::NodeSet; use syntax::attr; -mod common; +pub mod common; pub mod link; pub mod collector; pub mod trans_item; diff --git a/src/librustc_trans_utils/trans_item.rs b/src/librustc_trans_utils/trans_item.rs index 0ada39d7d27..817ceefeb7f 100644 --- a/src/librustc_trans_utils/trans_item.rs +++ b/src/librustc_trans_utils/trans_item.rs @@ -335,6 +335,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { output); } }, + ty::TyForeign(did) => self.push_def_path(did, output), ty::TyFnDef(..) | ty::TyFnPtr(_) => { let sig = t.fn_sig(self.tcx); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 7c9497badfb..c7f7e62fd61 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -928,7 +928,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let span = path.span; match path.def { - Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) | Def::Union(did) => { + Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) | + Def::Union(did) | Def::TyForeign(did) => { assert_eq!(opt_self_ty, None); self.prohibit_type_params(path.segments.split_last().unwrap().1); self.ast_path_to_ty(span, did, path.segments.last().unwrap()) diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 9c6cacb9d25..7b35b466830 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -13,7 +13,7 @@ //! A cast `e as U` is valid if one of the following holds: //! * `e` has type `T` and `T` coerces to `U`; *coercion-cast* //! * `e` has type `*T`, `U` is `*U_0`, and either `U_0: Sized` or -//! unsize_kind(`T`) = unsize_kind(`U_0`); *ptr-ptr-cast* +//! pointer_kind(`T`) = pointer_kind(`U_0`); *ptr-ptr-cast* //! * `e` has type `*T` and `U` is a numeric type, while `T: Sized`; *ptr-addr-cast* //! * `e` is an integer and `U` is `*U_0`, while `U_0: Sized`; *addr-ptr-cast* //! * `e` has type `T` and `T` and `U` are any numeric types; *numeric-cast* @@ -26,7 +26,7 @@ //! * `e` is a function pointer type and `U` is an integer; *fptr-addr-cast* //! //! where `&.T` and `*T` are references of either mutability, -//! and where unsize_kind(`T`) is the kind of the unsize info +//! and where pointer_kind(`T`) is the kind of the unsize info //! in `T` - the vtable for a trait definition (e.g. `fmt::Display` or //! `Iterator`, not `Iterator<Item=u8>`) or a length (or `()` if `T: Sized`). //! @@ -64,11 +64,16 @@ pub struct CastCheck<'tcx> { span: Span, } -/// The kind of the unsize info (length or vtable) - we only allow casts between -/// fat pointers if their unsize-infos have the same kind. +/// The kind of pointer and associated metadata (thin, length or vtable) - we +/// only allow casts between fat pointers if their metadata have the same +/// kind. #[derive(Copy, Clone, PartialEq, Eq)] -enum UnsizeKind<'tcx> { +enum PointerKind<'tcx> { + /// No metadata attached, ie pointer to sized type or foreign type + Thin, + /// A trait object Vtable(Option<DefId>), + /// Slice Length, /// The unsize info of this projection OfProjection(&'tcx ty::ProjectionTy<'tcx>), @@ -79,22 +84,28 @@ enum UnsizeKind<'tcx> { impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// Returns the kind of unsize information of t, or None /// if t is sized or it is unknown. - fn unsize_kind(&self, t: Ty<'tcx>) -> Option<UnsizeKind<'tcx>> { + fn pointer_kind(&self, t: Ty<'tcx>, span: Span) -> PointerKind<'tcx> { + if self.type_is_known_to_be_sized(t, span) { + return PointerKind::Thin; + } + match t.sty { - ty::TySlice(_) | ty::TyStr => Some(UnsizeKind::Length), + ty::TySlice(_) | ty::TyStr => PointerKind::Length, ty::TyDynamic(ref tty, ..) => - Some(UnsizeKind::Vtable(tty.principal().map(|p| p.def_id()))), + PointerKind::Vtable(tty.principal().map(|p| p.def_id())), ty::TyAdt(def, substs) if def.is_struct() => { // FIXME(arielb1): do some kind of normalization match def.struct_variant().fields.last() { - None => None, - Some(f) => self.unsize_kind(f.ty(self.tcx, substs)), + None => PointerKind::Thin, + Some(f) => self.pointer_kind(f.ty(self.tcx, substs), span), } } + // Pointers to foreign types are thin, despite being unsized + ty::TyForeign(..) => PointerKind::Thin, // We should really try to normalize here. - ty::TyProjection(ref pi) => Some(UnsizeKind::OfProjection(pi)), - ty::TyParam(ref p) => Some(UnsizeKind::OfParam(p)), - _ => None, + ty::TyProjection(ref pi) => PointerKind::OfProjection(pi), + ty::TyParam(ref p) => PointerKind::OfParam(p), + _ => panic!(), } } } @@ -446,20 +457,23 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { debug!("check_ptr_ptr_cast m_expr={:?} m_cast={:?}", m_expr, m_cast); // ptr-ptr cast. vtables must match. - // Cast to sized is OK - if fcx.type_is_known_to_be_sized(m_cast.ty, self.span) { + // Cast to thin pointer is OK + let cast_kind = fcx.pointer_kind(m_cast.ty, self.span); + if cast_kind == PointerKind::Thin { return Ok(CastKind::PtrPtrCast); } - // sized -> unsized? report invalid cast (don't complain about vtable kinds) - if fcx.type_is_known_to_be_sized(m_expr.ty, self.span) { + // thin -> fat? report invalid cast (don't complain about vtable kinds) + let expr_kind = fcx.pointer_kind(m_expr.ty, self.span); + if expr_kind == PointerKind::Thin { return Err(CastError::SizedUnsizedCast); } // vtable kinds must match - match (fcx.unsize_kind(m_cast.ty), fcx.unsize_kind(m_expr.ty)) { - (Some(a), Some(b)) if a == b => Ok(CastKind::PtrPtrCast), - _ => Err(CastError::DifferingKinds), + if cast_kind == expr_kind { + Ok(CastKind::PtrPtrCast) + } else { + Err(CastError::DifferingKinds) } } @@ -467,9 +481,9 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { fcx: &FnCtxt<'a, 'gcx, 'tcx>, m_cast: &'tcx ty::TypeAndMut<'tcx>) -> Result<CastKind, CastError> { - // fptr-ptr cast. must be to sized ptr + // fptr-ptr cast. must be to thin ptr - if fcx.type_is_known_to_be_sized(m_cast.ty, self.span) { + if fcx.pointer_kind(m_cast.ty, self.span) == PointerKind::Thin { Ok(CastKind::FnPtrPtrCast) } else { Err(CastError::IllegalCast) @@ -480,9 +494,9 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { fcx: &FnCtxt<'a, 'gcx, 'tcx>, m_expr: &'tcx ty::TypeAndMut<'tcx>) -> Result<CastKind, CastError> { - // ptr-addr cast. must be from sized ptr + // ptr-addr cast. must be from thin ptr - if fcx.type_is_known_to_be_sized(m_expr.ty, self.span) { + if fcx.pointer_kind(m_expr.ty, self.span) == PointerKind::Thin { Ok(CastKind::PtrAddrCast) } else { Err(CastError::NeedViaThinPtr) @@ -519,7 +533,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { m_cast: &'tcx ty::TypeAndMut<'tcx>) -> Result<CastKind, CastError> { // ptr-addr cast. pointer must be thin. - if fcx.type_is_known_to_be_sized(m_cast.ty, self.span) { + if fcx.pointer_kind(m_cast.ty, self.span) == PointerKind::Thin { Ok(CastKind::AddrPtrCast) } else { Err(CastError::IllegalCast) diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 78941cb3a56..a24f420af80 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -414,6 +414,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { ty::TyAdt(def, _) => { self.assemble_inherent_impl_candidates_for_type(def.did); } + ty::TyForeign(did) => { + self.assemble_inherent_impl_candidates_for_type(did); + } ty::TyParam(p) => { self.assemble_inherent_candidates_from_param(self_ty, p); } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 23148406a11..8613ec86b4a 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -451,6 +451,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn is_local(ty: Ty) -> bool { match ty.sty { ty::TyAdt(def, _) => def.did.is_local(), + ty::TyForeign(did) => did.is_local(), ty::TyDynamic(ref tr, ..) => tr.principal() .map_or(false, |p| p.def_id().is_local()), diff --git a/src/librustc_typeck/coherence/inherent_impls.rs b/src/librustc_typeck/coherence/inherent_impls.rs index 15e15abfb36..c56a3b91ca3 100644 --- a/src/librustc_typeck/coherence/inherent_impls.rs +++ b/src/librustc_typeck/coherence/inherent_impls.rs @@ -117,6 +117,9 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyAdt(def, _) => { self.check_def_id(item, def.did); } + ty::TyForeign(did) => { + self.check_def_id(item, did); + } ty::TyDynamic(ref data, ..) if data.principal().is_some() => { self.check_def_id(item, data.principal().unwrap().def_id()); } diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index 097720adad4..a5edc95b79b 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -68,10 +68,10 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> { } // In addition to the above rules, we restrict impls of defaulted traits - // so that they can only be implemented on structs/enums. To see why this - // restriction exists, consider the following example (#22978). Imagine - // that crate A defines a defaulted trait `Foo` and a fn that operates - // on pairs of types: + // so that they can only be implemented on nominal types, such as structs, + // enums or foreign types. To see why this restriction exists, consider the + // following example (#22978). Imagine that crate A defines a defaulted trait + // `Foo` and a fn that operates on pairs of types: // // ``` // // Crate A @@ -109,11 +109,12 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> { let self_ty = trait_ref.self_ty(); let opt_self_def_id = match self_ty.sty { ty::TyAdt(self_def, _) => Some(self_def.did), + ty::TyForeign(did) => Some(did), _ => None, }; let msg = match opt_self_def_id { - // We only want to permit structs/enums, but not *all* structs/enums. + // We only want to permit nominal types, but not *all* nominal types. // They must be local to the current crate, so that people // can't do `unsafe impl Send for Rc<SomethingLocal>` or // `impl !Send for Box<SomethingLocalAndSend>`. diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 68ba1b4c44c..75e864d07a6 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -916,7 +916,8 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, NodeForeignItem(item) => { match item.node { ForeignItemStatic(..) => &no_generics, - ForeignItemFn(_, _, ref generics) => generics + ForeignItemFn(_, _, ref generics) => generics, + ForeignItemType => &no_generics, } } @@ -1094,7 +1095,8 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let substs = Substs::identity_for_item(tcx, def_id); tcx.mk_fn_def(def_id, substs) } - ForeignItemStatic(ref t, _) => icx.to_ty(t) + ForeignItemStatic(ref t, _) => icx.to_ty(t), + ForeignItemType => tcx.mk_foreign(def_id), } } @@ -1363,7 +1365,8 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, NodeForeignItem(item) => { match item.node { ForeignItemStatic(..) => &no_generics, - ForeignItemFn(_, _, ref generics) => generics + ForeignItemFn(_, _, ref generics) => generics, + ForeignItemType => &no_generics, } } diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 857b35158f2..ef6552c8e33 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -305,7 +305,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { match ty.sty { ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | - ty::TyStr | ty::TyNever => { + ty::TyStr | ty::TyNever | ty::TyForeign(..) => { // leaf type -- noop } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 4e8bf5f9109..f8fea643d5e 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -419,6 +419,8 @@ pub enum ItemEnum { ForeignFunctionItem(Function), /// `static`s from an extern block ForeignStaticItem(Static), + /// `type`s from an extern block + ForeignTypeItem, MacroItem(Macro), PrimitiveItem(PrimitiveType), AssociatedConstItem(Type, Option<String>), @@ -1646,6 +1648,7 @@ pub enum TypeKind { Trait, Variant, Typedef, + Foreign, } pub trait GetDefId { @@ -2027,6 +2030,17 @@ impl<'tcx> Clean<Type> for Ty<'tcx> { is_generic: false, } } + ty::TyForeign(did) => { + inline::record_extern_fqn(cx, did, TypeKind::Foreign); + let path = external_path(cx, &cx.tcx.item_name(did), + None, false, vec![], Substs::empty()); + ResolvedPath { + path: path, + typarams: None, + did: did, + is_generic: false, + } + } ty::TyDynamic(ref obj, ref reg) => { if let Some(principal) = obj.principal() { let did = principal.def_id(); @@ -2840,6 +2854,9 @@ impl Clean<Item> for hir::ForeignItem { expr: "".to_string(), }) } + hir::ForeignItemType => { + ForeignTypeItem + } }; Item { name: Some(self.name.clean(cx)), diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs index f584c4e2f4d..c9c5f01f0ae 100644 --- a/src/librustdoc/html/item_type.rs +++ b/src/librustdoc/html/item_type.rs @@ -41,6 +41,7 @@ pub enum ItemType { Constant = 17, AssociatedConst = 18, Union = 19, + ForeignType = 20, } @@ -82,6 +83,7 @@ impl<'a> From<&'a clean::Item> for ItemType { clean::AssociatedConstItem(..) => ItemType::AssociatedConst, clean::AssociatedTypeItem(..) => ItemType::AssociatedType, clean::DefaultImplItem(..) => ItemType::Impl, + clean::ForeignTypeItem => ItemType::ForeignType, clean::StrippedItem(..) => unreachable!(), } } @@ -100,6 +102,7 @@ impl From<clean::TypeKind> for ItemType { clean::TypeKind::Const => ItemType::Constant, clean::TypeKind::Variant => ItemType::Variant, clean::TypeKind::Typedef => ItemType::Typedef, + clean::TypeKind::Foreign => ItemType::ForeignType, } } } @@ -127,6 +130,7 @@ impl ItemType { ItemType::AssociatedType => "associatedtype", ItemType::Constant => "constant", ItemType::AssociatedConst => "associatedconstant", + ItemType::ForeignType => "foreigntype", } } @@ -139,7 +143,8 @@ impl ItemType { ItemType::Typedef | ItemType::Trait | ItemType::Primitive | - ItemType::AssociatedType => NameSpace::Type, + ItemType::AssociatedType | + ItemType::ForeignType => NameSpace::Type, ItemType::ExternCrate | ItemType::Import | diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index d538428a7e9..ac2cb1665a7 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2044,6 +2044,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, ItemType::Primitive => ("primitives", "Primitive Types"), ItemType::AssociatedType => ("associated-types", "Associated Types"), ItemType::AssociatedConst => ("associated-consts", "Associated Constants"), + ItemType::ForeignType => ("foreign-types", "Foreign Types"), }; write!(w, "<h2 id='{id}' class='section-header'>\ <a href=\"#{id}\">{name}</a></h2>\n<table>", @@ -3679,7 +3680,7 @@ fn sidebar_module(fmt: &mut fmt::Formatter, _it: &clean::Item, ItemType::Enum, ItemType::Constant, ItemType::Static, ItemType::Trait, ItemType::Function, ItemType::Typedef, ItemType::Union, ItemType::Impl, ItemType::TyMethod, ItemType::Method, ItemType::StructField, ItemType::Variant, - ItemType::AssociatedType, ItemType::AssociatedConst] { + ItemType::AssociatedType, ItemType::AssociatedConst, ItemType::ForeignType] { if items.iter().any(|it| { if let clean::DefaultImplItem(..) = it.inner { false @@ -3708,6 +3709,7 @@ fn sidebar_module(fmt: &mut fmt::Formatter, _it: &clean::Item, ItemType::Primitive => ("primitives", "Primitive Types"), ItemType::AssociatedType => ("associated-types", "Associated Types"), ItemType::AssociatedConst => ("associated-consts", "Associated Constants"), + ItemType::ForeignType => ("foreign-types", "Foreign Types"), }; sidebar.push_str(&format!("<li><a href=\"#{id}\">{name}</a></li>", id = short, diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index 146629486fa..959543404d8 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -90,7 +90,7 @@ impl<'a> fold::DocFolder for Stripper<'a> { clean::VariantItem(..) | clean::MethodItem(..) | clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) | clean::ConstantItem(..) | clean::UnionItem(..) | - clean::AssociatedConstItem(..) => { + clean::AssociatedConstItem(..) | clean::ForeignTypeItem => { if i.def_id.is_local() { if !self.access_levels.is_exported(i.def_id) { return None; diff --git a/src/libstd/process.rs b/src/libstd/process.rs index c19ece6a314..35c33f40253 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -10,25 +10,66 @@ //! A module for working with processes. //! -//! # Examples +//! This module is mostly concerned with spawning and interacting with child +//! processes, but it also provides [`abort`] and [`exit`] for terminating the +//! current process. //! -//! Basic usage where we try to execute the `cat` shell command: +//! # Spawning a process //! -//! ```should_panic +//! The [`Command`] struct is used to configure and spawn processes: +//! +//! ``` //! use std::process::Command; //! -//! let mut child = Command::new("/bin/cat") -//! .arg("file.txt") -//! .spawn() -//! .expect("failed to execute child"); +//! let output = Command::new("echo") +//! .arg("Hello world") +//! .output() +//! .expect("Failed to execute command"); +//! +//! assert_eq!(b"Hello world\n", output.stdout.as_slice()); +//! ``` +//! +//! Several methods on [`Command`], such as [`spawn`] or [`output`], can be used +//! to spawn a process. In particular, [`output`] spawns the child process and +//! waits until the process terminates, while [`spawn`] will return a [`Child`] +//! that represents the spawned child process. +//! +//! # Handling I/O +//! +//! The [`stdout`], [`stdin`], and [`stderr`] of a child process can be +//! configured by passing an [`Stdio`] to the corresponding method on +//! [`Command`]. Once spawned, they can be accessed from the [`Child`]. For +//! example, piping output from one command into another command can be done +//! like so: +//! +//! ```no_run +//! use std::process::{Command, Stdio}; //! -//! let ecode = child.wait() -//! .expect("failed to wait on child"); +//! // stdout must be configured with `Stdio::piped` in order to use +//! // `echo_child.stdout` +//! let echo_child = Command::new("echo") +//! .arg("Oh no, a tpyo!") +//! .stdout(Stdio::piped()) +//! .spawn() +//! .expect("Failed to start echo process"); +//! +//! // Note that `echo_child` is moved here, but we won't be needing +//! // `echo_child` anymore +//! let echo_out = echo_child.stdout.expect("Failed to open echo stdout"); +//! +//! let mut sed_child = Command::new("sed") +//! .arg("s/tpyo/typo/") +//! .stdin(Stdio::from(echo_out)) +//! .stdout(Stdio::piped()) +//! .spawn() +//! .expect("Failed to start sed process"); //! -//! assert!(ecode.success()); +//! let output = sed_child.wait_with_output().expect("Failed to wait on sed"); +//! assert_eq!(b"Oh no, a typo!\n", output.stdout.as_slice()); //! ``` //! -//! Calling a command with input and reading its output: +//! Note that [`ChildStderr`] and [`ChildStdout`] implement [`Write`] and +//! [`ChildStdin`] implements [`Read`]: //! //! ```no_run //! use std::process::{Command, Stdio}; @@ -52,6 +93,26 @@ //! //! assert_eq!(b"test", output.stdout.as_slice()); //! ``` +//! +//! [`abort`]: fn.abort.html +//! [`exit`]: fn.exit.html +//! +//! [`Command`]: struct.Command.html +//! [`spawn`]: struct.Command.html#method.spawn +//! [`output`]: struct.Command.html#method.output +//! +//! [`Child`]: struct.Child.html +//! [`ChildStdin`]: struct.ChildStdin.html +//! [`ChildStdout`]: struct.ChildStdout.html +//! [`ChildStderr`]: struct.ChildStderr.html +//! [`Stdio`]: struct.Stdio.html +//! +//! [`stdout`]: struct.Command.html#method.stdout +//! [`stdin`]: struct.Command.html#method.stdin +//! [`stderr`]: struct.Command.html#method.stderr +//! +//! [`Write`]: ../io/trait.Write.html +//! [`Read`]: ../io/trait.Read.html #![stable(feature = "process", since = "1.0.0")] diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 090fc193b38..d3995d95792 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -2007,13 +2007,16 @@ pub enum ForeignItemKind { /// A foreign static item (`static ext: u8`), with optional mutability /// (the boolean is true when mutable) Static(P<Ty>, bool), + /// A foreign type + Ty, } impl ForeignItemKind { pub fn descriptive_variant(&self) -> &str { match *self { ForeignItemKind::Fn(..) => "foreign function", - ForeignItemKind::Static(..) => "foreign static item" + ForeignItemKind::Static(..) => "foreign static item", + ForeignItemKind::Ty => "foreign type", } } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 02aba8a3612..30451ec757a 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -404,6 +404,9 @@ declare_features! ( // `crate` as visibility modifier, synonymous to `pub(crate)` (active, crate_visibility_modifier, "1.23.0", Some(45388)), + + // extern types + (active, extern_types, "1.23.0", Some(43467)), ); declare_features! ( @@ -1398,13 +1401,23 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) { - let links_to_llvm = match attr::first_attr_value_str_by_name(&i.attrs, "link_name") { - Some(val) => val.as_str().starts_with("llvm."), - _ => false - }; - if links_to_llvm { - gate_feature_post!(&self, link_llvm_intrinsics, i.span, - "linking to LLVM intrinsics is experimental"); + match i.node { + ast::ForeignItemKind::Fn(..) | + ast::ForeignItemKind::Static(..) => { + let link_name = attr::first_attr_value_str_by_name(&i.attrs, "link_name"); + let links_to_llvm = match link_name { + Some(val) => val.as_str().starts_with("llvm."), + _ => false + }; + if links_to_llvm { + gate_feature_post!(&self, link_llvm_intrinsics, i.span, + "linking to LLVM intrinsics is experimental"); + } + } + ast::ForeignItemKind::Ty => { + gate_feature_post!(&self, extern_types, i.span, + "extern types are experimental"); + } } visit::walk_foreign_item(self, i) diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 518386a2ad2..fea49424dc8 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1069,6 +1069,7 @@ pub fn noop_fold_foreign_item<T: Folder>(ni: ForeignItem, folder: &mut T) -> For ForeignItemKind::Static(t, m) => { ForeignItemKind::Static(folder.fold_ty(t), m) } + ForeignItemKind::Ty => ForeignItemKind::Ty, }, span: folder.new_span(ni.span) } diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs index db49ab10343..b8151819bff 100644 --- a/src/libsyntax/json.rs +++ b/src/libsyntax/json.rs @@ -153,17 +153,15 @@ impl Diagnostic { fn from_diagnostic_builder(db: &DiagnosticBuilder, je: &JsonEmitter) -> Diagnostic { - let sugg = db.suggestions.iter().flat_map(|sugg| { - je.render(sugg).into_iter().map(move |rendered| { - Diagnostic { - message: sugg.msg.clone(), - code: None, - level: "help", - spans: DiagnosticSpan::from_suggestion(sugg, je), - children: vec![], - rendered: Some(rendered), - } - }) + let sugg = db.suggestions.iter().map(|sugg| { + Diagnostic { + message: sugg.msg.clone(), + code: None, + level: "help", + spans: DiagnosticSpan::from_suggestion(sugg, je), + children: vec![], + rendered: None, + } }); Diagnostic { message: db.message(), @@ -356,9 +354,3 @@ impl DiagnosticCode { }) } } - -impl JsonEmitter { - fn render(&self, suggestion: &CodeSuggestion) -> Vec<String> { - suggestion.splice_lines(&*self.cm).iter().map(|line| line.0.to_owned()).collect() - } -} diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index e96a5417aff..a3a265450ab 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5687,6 +5687,24 @@ impl<'a> Parser<'a> { }) } + /// Parse a type from a foreign module + fn parse_item_foreign_type(&mut self, vis: ast::Visibility, lo: Span, attrs: Vec<Attribute>) + -> PResult<'a, ForeignItem> { + self.expect_keyword(keywords::Type)?; + + let ident = self.parse_ident()?; + let hi = self.span; + self.expect(&token::Semi)?; + Ok(ast::ForeignItem { + ident: ident, + attrs: attrs, + node: ForeignItemKind::Ty, + id: ast::DUMMY_NODE_ID, + span: lo.to(hi), + vis: vis + }) + } + /// Parse extern crate links /// /// # Examples @@ -6161,6 +6179,10 @@ impl<'a> Parser<'a> { if self.check_keyword(keywords::Fn) { return Ok(Some(self.parse_item_foreign_fn(visibility, lo, attrs)?)); } + // FOREIGN TYPE ITEM + if self.check_keyword(keywords::Type) { + return Ok(Some(self.parse_item_foreign_type(visibility, lo, attrs)?)); + } // FIXME #5668: this will occur for a macro invocation: match self.parse_macro_use_or_failure(attrs, true, false, lo, visibility)? { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 656a51c6637..8a970fd4098 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1112,6 +1112,13 @@ impl<'a> State<'a> { self.end()?; // end the head-ibox self.end() // end the outer cbox } + ast::ForeignItemKind::Ty => { + self.head(&visibility_qualified(&item.vis, "type"))?; + self.print_ident(item.ident)?; + self.s.word(";")?; + self.end()?; // end the head-ibox + self.end() // end the outer cbox + } } } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 4198055f670..96e47a6cc0f 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -477,6 +477,7 @@ pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, foreign_item: &'a visitor.visit_generics(generics) } ForeignItemKind::Static(ref typ, _) => visitor.visit_ty(typ), + ForeignItemKind::Ty => (), } walk_list!(visitor, visit_attribute, &foreign_item.attrs); diff --git a/src/test/compile-fail/extern-types-distinct-types.rs b/src/test/compile-fail/extern-types-distinct-types.rs new file mode 100644 index 00000000000..8b434bbfc6d --- /dev/null +++ b/src/test/compile-fail/extern-types-distinct-types.rs @@ -0,0 +1,22 @@ +// Copyright 2017 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(extern_types)] + +extern { + type A; + type B; +} + +fn foo(r: &A) -> &B { + r //~ ERROR mismatched types +} + +fn main() { } diff --git a/src/test/compile-fail/extern-types-not-sync-send.rs b/src/test/compile-fail/extern-types-not-sync-send.rs new file mode 100644 index 00000000000..2f00cf812e4 --- /dev/null +++ b/src/test/compile-fail/extern-types-not-sync-send.rs @@ -0,0 +1,28 @@ +// Copyright 2017 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Make sure extern types are !Sync and !Send. + +#![feature(extern_types)] + +extern { + type A; +} + +fn assert_sync<T: ?Sized + Sync>() { } +fn assert_send<T: ?Sized + Send>() { } + +fn main() { + assert_sync::<A>(); + //~^ ERROR the trait bound `A: std::marker::Sync` is not satisfied + + assert_send::<A>(); + //~^ ERROR the trait bound `A: std::marker::Send` is not satisfied +} diff --git a/src/test/compile-fail/extern-types-unsized.rs b/src/test/compile-fail/extern-types-unsized.rs new file mode 100644 index 00000000000..faa27894806 --- /dev/null +++ b/src/test/compile-fail/extern-types-unsized.rs @@ -0,0 +1,43 @@ +// Copyright 2017 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Make sure extern types are !Sized. + +#![feature(extern_types)] + +extern { + type A; +} + +struct Foo { + x: u8, + tail: A, +} + +struct Bar<T: ?Sized> { + x: u8, + tail: T, +} + +fn assert_sized<T>() { } + +fn main() { + assert_sized::<A>(); + //~^ ERROR the trait bound `A: std::marker::Sized` is not satisfied + + assert_sized::<Foo>(); + //~^ ERROR the trait bound `A: std::marker::Sized` is not satisfied + + assert_sized::<Bar<A>>(); + //~^ ERROR the trait bound `A: std::marker::Sized` is not satisfied + + assert_sized::<Bar<Bar<A>>>(); + //~^ ERROR the trait bound `A: std::marker::Sized` is not satisfied +} diff --git a/src/test/compile-fail/feature-gate-extern_types.rs b/src/test/compile-fail/feature-gate-extern_types.rs new file mode 100644 index 00000000000..1203b598df3 --- /dev/null +++ b/src/test/compile-fail/feature-gate-extern_types.rs @@ -0,0 +1,15 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern { + type T; //~ ERROR extern types are experimental +} + +fn main() {} diff --git a/src/test/compile-fail/issue-27842.rs b/src/test/compile-fail/issue-27842.rs index 8c71761df2f..eb28e36dc07 100644 --- a/src/test/compile-fail/issue-27842.rs +++ b/src/test/compile-fail/issue-27842.rs @@ -14,7 +14,7 @@ fn main() { let _ = tup[0]; //~^ ERROR cannot index into a value of type //~| HELP to access tuple elements, use - //~| SUGGESTION let _ = tup.0 + //~| SUGGESTION tup.0 // the case where we show just a general hint let i = 0_usize; diff --git a/src/test/run-make/extern-fn-with-extern-types/Makefile b/src/test/run-make/extern-fn-with-extern-types/Makefile new file mode 100644 index 00000000000..8977e14c3ad --- /dev/null +++ b/src/test/run-make/extern-fn-with-extern-types/Makefile @@ -0,0 +1,5 @@ +-include ../tools.mk + +all: $(call NATIVE_STATICLIB,ctest) + $(RUSTC) test.rs + $(call RUN,test) || exit 1 diff --git a/src/test/run-make/extern-fn-with-extern-types/ctest.c b/src/test/run-make/extern-fn-with-extern-types/ctest.c new file mode 100644 index 00000000000..c3d6166fb12 --- /dev/null +++ b/src/test/run-make/extern-fn-with-extern-types/ctest.c @@ -0,0 +1,17 @@ +// ignore-license +#include <stdio.h> +#include <stdint.h> + +typedef struct data { + uint32_t magic; +} data; + +data* data_create(uint32_t magic) { + static data d; + d.magic = magic; + return &d; +} + +uint32_t data_get(data* p) { + return p->magic; +} diff --git a/src/test/run-make/extern-fn-with-extern-types/test.rs b/src/test/run-make/extern-fn-with-extern-types/test.rs new file mode 100644 index 00000000000..9d6c87885b1 --- /dev/null +++ b/src/test/run-make/extern-fn-with-extern-types/test.rs @@ -0,0 +1,27 @@ +// Copyright 2017 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(extern_types)] + +#[link(name = "ctest", kind = "static")] +extern { + type data; + + fn data_create(magic: u32) -> *mut data; + fn data_get(data: *mut data) -> u32; +} + +const MAGIC: u32 = 0xdeadbeef; +fn main() { + unsafe { + let data = data_create(MAGIC); + assert_eq!(data_get(data), MAGIC); + } +} diff --git a/src/test/run-pass/extern-types-inherent-impl.rs b/src/test/run-pass/extern-types-inherent-impl.rs new file mode 100644 index 00000000000..4e44af36900 --- /dev/null +++ b/src/test/run-pass/extern-types-inherent-impl.rs @@ -0,0 +1,27 @@ +// Copyright 2017 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that inherent impls can be defined for extern types. + +#![feature(extern_types)] + +extern { + type A; +} + +impl A { + fn foo(&self) { } +} + +fn use_foo(x: &A) { + x.foo(); +} + +fn main() { } diff --git a/src/test/run-pass/extern-types-manual-sync-send.rs b/src/test/run-pass/extern-types-manual-sync-send.rs new file mode 100644 index 00000000000..c6530c3ea77 --- /dev/null +++ b/src/test/run-pass/extern-types-manual-sync-send.rs @@ -0,0 +1,28 @@ +// Copyright 2017 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that unsafe impl for Sync/Send can be provided for extern types. + +#![feature(extern_types)] + +extern { + type A; +} + +unsafe impl Sync for A { } +unsafe impl Send for A { } + +fn assert_sync<T: ?Sized + Sync>() { } +fn assert_send<T: ?Sized + Send>() { } + +fn main() { + assert_sync::<A>(); + assert_send::<A>(); +} diff --git a/src/test/run-pass/extern-types-pointer-cast.rs b/src/test/run-pass/extern-types-pointer-cast.rs new file mode 100644 index 00000000000..628a570665a --- /dev/null +++ b/src/test/run-pass/extern-types-pointer-cast.rs @@ -0,0 +1,40 @@ +// Copyright 2017 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that pointers to extern types can be casted from/to usize, +// despite being !Sized. + +#![feature(extern_types)] + +extern { + type A; +} + +struct Foo { + x: u8, + tail: A, +} + +struct Bar<T: ?Sized> { + x: u8, + tail: T, +} + +#[cfg(target_pointer_width = "32")] +const MAGIC: usize = 0xdeadbeef; +#[cfg(target_pointer_width = "64")] +const MAGIC: usize = 0x12345678deadbeef; + +fn main() { + assert_eq!((MAGIC as *const A) as usize, MAGIC); + assert_eq!((MAGIC as *const Foo) as usize, MAGIC); + assert_eq!((MAGIC as *const Bar<A>) as usize, MAGIC); + assert_eq!((MAGIC as *const Bar<Bar<A>>) as usize, MAGIC); +} diff --git a/src/test/run-pass/extern-types-size_of_val.rs b/src/test/run-pass/extern-types-size_of_val.rs new file mode 100644 index 00000000000..0aabce99deb --- /dev/null +++ b/src/test/run-pass/extern-types-size_of_val.rs @@ -0,0 +1,26 @@ +// Copyright 2017 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(extern_types)] + +use std::mem::{size_of_val, align_of_val}; + +extern { + type A; +} + +fn main() { + let x: &A = unsafe { + &*(1usize as *const A) + }; + + assert_eq!(size_of_val(x), 0); + assert_eq!(align_of_val(x), 1); +} diff --git a/src/test/run-pass/extern-types-thin-pointer.rs b/src/test/run-pass/extern-types-thin-pointer.rs new file mode 100644 index 00000000000..c2444a58b5a --- /dev/null +++ b/src/test/run-pass/extern-types-thin-pointer.rs @@ -0,0 +1,51 @@ +// Copyright 2017 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that pointers and references to extern types are thin, ie they have the same size and +// alignment as a pointer to (). + +#![feature(extern_types)] + +use std::mem::{align_of, size_of}; + +extern { + type A; +} + +struct Foo { + x: u8, + tail: A, +} + +struct Bar<T: ?Sized> { + x: u8, + tail: T, +} + +fn assert_thin<T: ?Sized>() { + assert_eq!(size_of::<*const T>(), size_of::<*const ()>()); + assert_eq!(align_of::<*const T>(), align_of::<*const ()>()); + + assert_eq!(size_of::<*mut T>(), size_of::<*mut ()>()); + assert_eq!(align_of::<*mut T>(), align_of::<*mut ()>()); + + assert_eq!(size_of::<&T>(), size_of::<&()>()); + assert_eq!(align_of::<&T>(), align_of::<&()>()); + + assert_eq!(size_of::<&mut T>(), size_of::<&mut ()>()); + assert_eq!(align_of::<&mut T>(), align_of::<&mut ()>()); +} + +fn main() { + assert_thin::<A>(); + assert_thin::<Foo>(); + assert_thin::<Bar<A>>(); + assert_thin::<Bar<Bar<A>>>(); +} diff --git a/src/test/run-pass/extern-types-trait-impl.rs b/src/test/run-pass/extern-types-trait-impl.rs new file mode 100644 index 00000000000..0f61c936deb --- /dev/null +++ b/src/test/run-pass/extern-types-trait-impl.rs @@ -0,0 +1,35 @@ +// Copyright 2017 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that traits can be implemented for extern types. + +#![feature(extern_types)] + +extern { + type A; +} + +trait Foo { + fn foo(&self) { } +} + +impl Foo for A { + fn foo(&self) { } +} + +fn assert_foo<T: ?Sized + Foo>() { } + +fn use_foo<T: ?Sized + Foo>(x: &Foo) { + x.foo(); +} + +fn main() { + assert_foo::<A>(); +} diff --git a/src/test/ui/lint/unused_parens_json_suggestion.stderr b/src/test/ui/lint/unused_parens_json_suggestion.stderr index 4b4dd92855d..701334d8890 100644 --- a/src/test/ui/lint/unused_parens_json_suggestion.stderr +++ b/src/test/ui/lint/unused_parens_json_suggestion.stderr @@ -1 +1 @@ -{"message":"unnecessary parentheses around assigned value","code":null,"level":"warning","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":976,"byte_end":989,"line_start":22,"line_end":22,"column_start":14,"column_end":27,"is_primary":true,"text":[{"text":" let _a = (1 / (2 + 3));","highlight_start":14,"highlight_end":27}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"#[warn(unused_parens)] on by default","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":976,"byte_end":989,"line_start":22,"line_end":22,"column_start":14,"column_end":27,"is_primary":true,"text":[{"text":" let _a = (1 / (2 + 3));","highlight_start":14,"highlight_end":27}],"label":null,"suggested_replacement":"1 / (2 + 3)","expansion":null}],"children":[],"rendered":" let _a = 1 / (2 + 3);"}],"rendered":null} +{"message":"unnecessary parentheses around assigned value","code":null,"level":"warning","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":976,"byte_end":989,"line_start":22,"line_end":22,"column_start":14,"column_end":27,"is_primary":true,"text":[{"text":" let _a = (1 / (2 + 3));","highlight_start":14,"highlight_end":27}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"#[warn(unused_parens)] on by default","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":976,"byte_end":989,"line_start":22,"line_end":22,"column_start":14,"column_end":27,"is_primary":true,"text":[{"text":" let _a = (1 / (2 + 3));","highlight_start":14,"highlight_end":27}],"label":null,"suggested_replacement":"1 / (2 + 3)","expansion":null}],"children":[],"rendered":null}],"rendered":null} diff --git a/src/test/ui/lint/use_suggestion_json.rs b/src/test/ui/lint/use_suggestion_json.rs new file mode 100644 index 00000000000..20c24d64050 --- /dev/null +++ b/src/test/ui/lint/use_suggestion_json.rs @@ -0,0 +1,21 @@ +// Copyright 2017 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: --error-format json + +// The output for humans should just highlight the whole span without showing +// the suggested replacement, but we also want to test that suggested +// replacement only removes one set of parentheses, rather than naïvely +// stripping away any starting or ending parenthesis characters—hence this +// test of the JSON error format. + +fn main() { + let x: Iter; +} diff --git a/src/test/ui/lint/use_suggestion_json.stderr b/src/test/ui/lint/use_suggestion_json.stderr new file mode 100644 index 00000000000..2ebe212b93d --- /dev/null +++ b/src/test/ui/lint/use_suggestion_json.stderr @@ -0,0 +1,2 @@ +{"message":"cannot find type `Iter` in this scope","code":{"code":"E0412","explanation":"/nThe type name used is not in scope./n/nErroneous code examples:/n/n```compile_fail,E0412/nimpl Something {} // error: type name `Something` is not in scope/n/n// or:/n/ntrait Foo {/n fn bar(N); // error: type name `N` is not in scope/n}/n/n// or:/n/nfn foo(x: T) {} // type name `T` is not in scope/n```/n/nTo fix this error, please verify you didn't misspell the type name, you did/ndeclare it or imported it into the scope. Examples:/n/n```/nstruct Something;/n/nimpl Something {} // ok!/n/n// or:/n/ntrait Foo {/n type N;/n/n fn bar(_: Self::N); // ok!/n}/n/n// or:/n/nfn foo<T>(x: T) {} // ok!/n```/n/nAnother case that causes this error is when a type is imported into a parent/nmodule. To fix this, you can follow the suggestion and use File directly or/n`use super::File;` which will import the types from the parent namespace. An/nexample that causes this error is below:/n/n```compile_fail,E0412/nuse std::fs::File;/n/nmod foo {/n fn some_function(f: File) {}/n}/n```/n/n```/nuse std::fs::File;/n/nmod foo {/n // either/n use super::File;/n // or/n // use std::fs::File;/n fn foo(f: File) {}/n}/n# fn main() {} // don't insert it for us; that'll break imports/n```/n"},"level":"error","spans":[{"file_name":"$DIR/use_suggestion_json.rs","byte_start":862,"byte_end":866,"line_start":20,"line_end":20,"column_start":12,"column_end":16,"is_primary":true,"text":[{"text":" let x: Iter;","highlight_start":12,"highlight_end":16}],"label":"not found in this scope","suggested_replacement":null,"expansion":null}],"children":[{"message":"possible candidates are found in other modules, you can import them into scope","code":null,"level":"help","spans":[{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::collections::binary_heap::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::collections::btree_map::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::collections::btree_set::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::collections::hash_map::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::collections::hash_set::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::collections::linked_list::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::collections::vec_deque::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::option::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::path::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::result::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::slice::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::sync::mpsc::Iter;/n/n","expansion":null}],"children":[],"rendered":null}],"rendered":null} +{"message":"aborting due to previous error","code":null,"level":"error","spans":[],"children":[],"rendered":null} diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs index 77ee93c3007..8e9cd1a12fa 100644 --- a/src/tools/compiletest/src/json.rs +++ b/src/tools/compiletest/src/json.rs @@ -36,6 +36,7 @@ struct DiagnosticSpan { column_end: usize, is_primary: bool, label: Option<String>, + suggested_replacement: Option<String>, expansion: Option<Box<DiagnosticSpanMacroExpansion>>, } @@ -164,15 +165,15 @@ fn push_expected_errors(expected_errors: &mut Vec<Error>, } // If the message has a suggestion, register that. - if let Some(ref rendered) = diagnostic.rendered { - let start_line = primary_spans.iter().map(|s| s.line_start).min().expect("\ - every suggestion should have at least one span"); - for (index, line) in rendered.lines().enumerate() { - expected_errors.push(Error { - line_num: start_line + index, - kind: Some(ErrorKind::Suggestion), - msg: line.to_string(), - }); + for span in primary_spans { + if let Some(ref suggested_replacement) = span.suggested_replacement { + for (index, line) in suggested_replacement.lines().enumerate() { + expected_errors.push(Error { + line_num: span.line_start + index, + kind: Some(ErrorKind::Suggestion), + msg: line.to_string(), + }); + } } } |
