Merge branch 'master' into rustfmt-update

This commit is contained in:
Dustin Speckhals 2017-10-29 13:27:06 -04:00
commit d284815f72
100 changed files with 983 additions and 214 deletions

View File

@ -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++",
}
}
}

View File

@ -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

View File

@ -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

View File

@ -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/

View File

@ -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/

View File

@ -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

View File

@ -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

View File

@ -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)

@ -1 +1 @@
Subproject commit 808f482db94391fca1e04a9692b59e9eda8cfef9
Subproject commit 7db393dae740d84775b73f403123c866e94e3a5b

View File

@ -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",

View File

@ -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);

View File

@ -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,

View File

@ -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",
}
}
}

View File

@ -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
}
}
}

View File

@ -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),

View File

@ -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)
}

View File

@ -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)

View File

@ -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);
}
}
}

View File

@ -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

View File

@ -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 {

View File

@ -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())
}

View File

@ -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
}
}

View File

@ -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(_)) |

View File

@ -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);

View File

@ -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)

View File

@ -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),
}
}
}

View File

@ -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

View File

@ -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 |

View File

@ -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)
}

View File

@ -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]
}

View File

@ -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(..) | // ...

View File

@ -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| {

View File

@ -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,
}
}

View File

@ -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 => {

View File

@ -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

View File

@ -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);

View File

@ -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
}

View File

@ -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| {

View File

@ -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 => ()
}
}
}

View File

@ -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(_) |

View File

@ -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 {

View File

@ -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.

View File

@ -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)

View File

@ -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;

View File

@ -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(..) => {

View File

@ -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);

View File

@ -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);
}
}
}
}
}

View File

@ -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) => {

View File

@ -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![],
})
}
}
}
}

View File

@ -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
}

View File

@ -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)

View File

@ -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);

View File

@ -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" => {

View File

@ -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

View File

@ -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))
}
}

View File

@ -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,

View File

@ -230,4 +230,3 @@ fn predefine_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
ccx.instances().borrow_mut().insert(instance, lldecl);
}

View File

@ -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) => {

View File

@ -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)

View File

@ -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>

View File

@ -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;

View File

@ -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);

View File

@ -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())

View File

@ -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)

View File

@ -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);
}

View File

@ -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()),

View File

@ -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());
}

View File

@ -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>`.

View File

@ -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,
}
}

View File

@ -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
}

View File

@ -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)),

View File

@ -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 |

View File

@ -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,

View File

@ -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;

View File

@ -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");
//!
//! let ecode = child.wait()
//! .expect("failed to wait on child");
//!
//! assert!(ecode.success());
//! assert_eq!(b"Hello world\n", output.stdout.as_slice());
//! ```
//!
//! Calling a command with input and reading its output:
//! 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};
//!
//! // 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");
//!
//! 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());
//! ```
//!
//! 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")]

View File

@ -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",
}
}
}

View File

@ -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)

View File

@ -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)
}

View File

@ -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()
}
}

View File

@ -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)? {

View File

@ -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
}
}
}

View File

@ -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);

View File

@ -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() { }

View File

@ -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
}

View File

@ -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
}

View File

@ -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() {}

View File

@ -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;

View File

@ -0,0 +1,5 @@
-include ../tools.mk
all: $(call NATIVE_STATICLIB,ctest)
$(RUSTC) test.rs
$(call RUN,test) || exit 1

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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() { }

View File

@ -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>();
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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>>>();
}

View File

@ -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>();
}

View File

@ -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}

View File

@ -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;
}

File diff suppressed because one or more lines are too long

View File

@ -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(),
});
}
}
}